#3 Secret revocation implemented

This commit is contained in:
Stefan Kalscheuer 2016-10-15 18:36:49 +02:00
parent c3ad6b6edd
commit 048e4d12b4
3 changed files with 152 additions and 58 deletions

View File

@ -60,6 +60,7 @@ public class HTTPVaultConnector implements VaultConnector {
private static final String PATH_AUTH_USERPASS = "auth/userpass/login/"; private static final String PATH_AUTH_USERPASS = "auth/userpass/login/";
private static final String PATH_AUTH_APPID = "auth/app-id/"; private static final String PATH_AUTH_APPID = "auth/app-id/";
private static final String PATH_SECRET = "secret"; private static final String PATH_SECRET = "secret";
private static final String PATH_REVOKE = "sys/revoke/";
private final ObjectMapper jsonMapper; private final ObjectMapper jsonMapper;
@ -71,6 +72,7 @@ public class HTTPVaultConnector implements VaultConnector {
/** /**
* Create connector using hostname and schema. * Create connector using hostname and schema.
*
* @param hostname The hostname * @param hostname The hostname
* @param useTLS If TRUE, use HTTPS, otherwise HTTP * @param useTLS If TRUE, use HTTPS, otherwise HTTP
*/ */
@ -80,6 +82,7 @@ public class HTTPVaultConnector implements VaultConnector {
/** /**
* Create connector using hostname, schema and port. * Create connector using hostname, schema and port.
*
* @param hostname The hostname * @param hostname The hostname
* @param useTLS If TRUE, use HTTPS, otherwise HTTP * @param useTLS If TRUE, use HTTPS, otherwise HTTP
* @param port The port * @param port The port
@ -89,7 +92,8 @@ public class HTTPVaultConnector implements VaultConnector {
} }
/** /**
* Create connector using hostname, schame, port and path * Create connector using hostname, schame, port and path.
*
* @param hostname The hostname * @param hostname The hostname
* @param useTLS If TRUE, use HTTPS, otherwise HTTP * @param useTLS If TRUE, use HTTPS, otherwise HTTP
* @param port The port * @param port The port
@ -103,7 +107,8 @@ public class HTTPVaultConnector implements VaultConnector {
} }
/** /**
* Create connector using full URL * Create connector using full URL.
*
* @param baseURL The URL * @param baseURL The URL
*/ */
public HTTPVaultConnector(String baseURL) { public HTTPVaultConnector(String baseURL) {
@ -310,10 +315,26 @@ public class HTTPVaultConnector implements VaultConnector {
return requestPost(PATH_SECRET + "/" + key, param).equals(""); return requestPost(PATH_SECRET + "/" + key, param).equals("");
} }
@Override
public boolean revoke(String leaseID) throws VaultConnectorException {
if (!isAuthorized())
throw new AuthorizationRequiredException();
/* Request HTTP response and expect empty result */
String response = requestPut(PATH_REVOKE + leaseID, new HashMap<>());
return response.equals("");
}
@Override
public VaultResponse renew(String leaseID, Integer seconds) {
/* TODO */
return null;
}
/** /**
* Execute HTTP request using POST method. * Execute HTTP request using POST method.
*
* @param path URL path (relative to base) * @param path URL path (relative to base)
* @param payload Map of payload values (will be converted to JSON) * @param payload Map of payload values (will be converted to JSON)
* @return HTTP response * @return HTTP response
@ -341,6 +362,7 @@ public class HTTPVaultConnector implements VaultConnector {
/** /**
* Execute HTTP request using PUT method. * Execute HTTP request using PUT method.
*
* @param path URL path (relative to base) * @param path URL path (relative to base)
* @param payload Map of payload values (will be converted to JSON) * @param payload Map of payload values (will be converted to JSON)
* @return HTTP response * @return HTTP response
@ -367,9 +389,10 @@ public class HTTPVaultConnector implements VaultConnector {
/** /**
* Execute HTTP request using GET method. * Execute HTTP request using GET method.
*
* @param path URL path (relative to base) * @param path URL path (relative to base)
* @param payload Map of payload values (will be converted to JSON) * @param payload Map of payload values (will be converted to JSON)
* @return HTTP response * @return HTTP response
* @throws VaultConnectorException on connection error * @throws VaultConnectorException on connection error
*/ */
private String requestGet(final String path, final Map<String, String> payload) throws VaultConnectorException, URISyntaxException { private String requestGet(final String path, final Map<String, String> payload) throws VaultConnectorException, URISyntaxException {
@ -388,9 +411,10 @@ public class HTTPVaultConnector implements VaultConnector {
} }
/** /**
* Execute prepared HTTP request and return result * Execute prepared HTTP request and return result.
* @param base Prepares Request *
* @return HTTP response * @param base Prepares Request
* @return HTTP response
* @throws VaultConnectorException on connection error * @throws VaultConnectorException on connection error
*/ */
private String request(HttpRequestBase base) throws VaultConnectorException { private String request(HttpRequestBase base) throws VaultConnectorException {

View File

@ -26,13 +26,14 @@ import java.util.List;
* Vault Connector interface. * Vault Connector interface.
* Provides methods to connect with Vault backend and handle secrets. * Provides methods to connect with Vault backend and handle secrets.
* *
* @author Stefan Kalscheuer * @author Stefan Kalscheuer
* @since 0.1 * @since 0.1
*/ */
public interface VaultConnector { public interface VaultConnector {
/** /**
* Verify that vault connection is initialized. * Verify that vault connection is initialized.
* @return TRUE if correctly initialized *
* @return TRUE if correctly initialized
*/ */
boolean init(); boolean init();
@ -43,28 +44,32 @@ public interface VaultConnector {
/** /**
* Retrieve status of vault seal. * Retrieve status of vault seal.
* @return Seal status *
* @return Seal status
*/ */
SealResponse sealStatus(); SealResponse sealStatus();
/** /**
* Seal vault. * Seal vault.
* @return TRUE on success *
* @return TRUE on success
*/ */
boolean seal(); boolean seal();
/** /**
* Unseal vault. * Unseal vault.
* @param key A single master share key *
* @param reset Discard previously provided keys (optional) * @param key A single master share key
* @return TRUE on success * @param reset Discard previously provided keys (optional)
* @return TRUE on success
*/ */
SealResponse unseal(final String key, final Boolean reset); SealResponse unseal(final String key, final Boolean reset);
/** /**
* Unseal vault. * Unseal vault.
* @param key A single master share key *
* @return TRUE on success * @param key A single master share key
* @return TRUE on success
*/ */
default SealResponse unseal(final String key) { default SealResponse unseal(final String key) {
return unseal(key, null); return unseal(key, null);
@ -72,64 +77,71 @@ public interface VaultConnector {
/** /**
* Get all availale authentication backends. * Get all availale authentication backends.
* @return List of backends *
* @throws VaultConnectorException on error * @return List of backends
* @throws VaultConnectorException on error
*/ */
List<AuthBackend> getAuthBackends() throws VaultConnectorException; List<AuthBackend> getAuthBackends() throws VaultConnectorException;
/** /**
* Authorize to Vault using token. * Authorize to Vault using token.
* @param token The token *
* @return Token response * @param token The token
* @throws VaultConnectorException on error * @return Token response
* @throws VaultConnectorException on error
*/ */
TokenResponse authToken(final String token) throws VaultConnectorException; TokenResponse authToken(final String token) throws VaultConnectorException;
/** /**
* Authorize to Vault using username and password. * Authorize to Vault using username and password.
* @param username The username *
* @param password The password * @param username The username
* @return Authorization result * @param password The password
* @throws VaultConnectorException on error * @return Authorization result
* @throws VaultConnectorException on error
*/ */
AuthResponse authUserPass(final String username, final String password) throws VaultConnectorException; AuthResponse authUserPass(final String username, final String password) throws VaultConnectorException;
/** /**
* Authorize to Vault using AppID method. * Authorize to Vault using AppID method.
* @param appID The App ID *
* @param userID The User ID * @param appID The App ID
* @return TRUE on success * @param userID The User ID
* @throws VaultConnectorException on error * @return TRUE on success
* @throws VaultConnectorException on error
*/ */
AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException; AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException;
/** /**
* Register new App-ID with policy. * Register new App-ID with policy.
* @param appID The unique App-ID *
* @param policy The policy to associate with * @param appID The unique App-ID
* @param displayName Arbitrary name to display * @param policy The policy to associate with
* @return TRUE on success * @param displayName Arbitrary name to display
* @throws VaultConnectorException on error * @return TRUE on success
* @throws VaultConnectorException on error
*/ */
boolean registerAppId(final String appID, final String policy, final String displayName) throws VaultConnectorException; boolean registerAppId(final String appID, final String policy, final String displayName) throws VaultConnectorException;
/** /**
* Register User-ID with App-ID * Register User-ID with App-ID
* @param appID The App-ID *
* @param userID The User-ID * @param appID The App-ID
* @return TRUE on success * @param userID The User-ID
* @throws VaultConnectorException on error * @return TRUE on success
* @throws VaultConnectorException on error
*/ */
boolean registerUserId(final String appID, final String userID) throws VaultConnectorException; boolean registerUserId(final String appID, final String userID) throws VaultConnectorException;
/** /**
* Register new App-ID and User-ID at once. * Register new App-ID and User-ID at once.
* @param appID The App-ID *
* @param policy The policy to associate with * @param appID The App-ID
* @param displayName Arbitrary name to display * @param policy The policy to associate with
* @param userID The User-ID * @param displayName Arbitrary name to display
* @return TRUE on success * @param userID The User-ID
* @throws VaultConnectorException on error * @return TRUE on success
* @throws VaultConnectorException on error
*/ */
default boolean registerAppUserId(final String appID, final String policy, final String displayName, final String userID) throws VaultConnectorException { default boolean registerAppUserId(final String appID, final String policy, final String displayName, final String userID) throws VaultConnectorException {
return registerAppId(appID, policy, userID) && registerUserId(appID, userID); return registerAppId(appID, policy, userID) && registerUserId(appID, userID);
@ -137,32 +149,54 @@ public interface VaultConnector {
/** /**
* Get authorization status * Get authorization status
* @return TRUE, if successfully authorized *
* @return TRUE, if successfully authorized
*/ */
boolean isAuthorized(); boolean isAuthorized();
/** /**
* Retrieve secret form Vault. * Retrieve secret form Vault.
* @param key Secret identifier *
* @return Secret response * @param key Secret identifier
* @throws VaultConnectorException on error * @return Secret response
* @throws VaultConnectorException on error
*/ */
SecretResponse readSecret(final String key) throws VaultConnectorException; SecretResponse readSecret(final String key) throws VaultConnectorException;
/** /**
* List available secrets from Vault. * List available secrets from Vault.
* @param path Root path to search *
* @return List of secret keys * @param path Root path to search
* @throws VaultConnectorException on error * @return List of secret keys
* @throws VaultConnectorException on error
*/ */
List<String> listSecrets(final String path) throws VaultConnectorException; List<String> listSecrets(final String path) throws VaultConnectorException;
/** /**
* Write secret to Vault. * Write secret to Vault.
*
* @param key Secret path * @param key Secret path
* @param value Secret value * @param value Secret value
* @return TRUE on success * @return TRUE on success
* @throws VaultConnectorException on error * @throws VaultConnectorException on error
*/ */
boolean writeSecret(final String key, final String value) throws VaultConnectorException; boolean writeSecret(final String key, final String value) throws VaultConnectorException;
/**
* Revoke given lease immediately.
*
* @param leaseID the lease ID
* @return TRUE on success
* @throws VaultConnectorException on error
*/
boolean revoke(final String leaseID) throws VaultConnectorException;
/**
* Renew lease with given ID.
*
* @param leaseID the lase ID
* @param seconds number of seconds to extend lease time
* @return Renewed lease
*/
VaultResponse renew(final String leaseID, final Integer seconds);
} }

View File

@ -35,13 +35,10 @@ import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.util.List; import java.util.List;
import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.core.Is.is; import static org.hamcrest.core.Is.is;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.junit.Assume.assumeFalse; import static org.junit.Assume.*;
import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
/** /**
* JUnit Test for HTTP Vault connector. * JUnit Test for HTTP Vault connector.
@ -303,6 +300,45 @@ public class HTTPVaultConnectorTest {
} }
} }
/**
* Test revocation of secrets.
*/
@Test
public void revokeTest() {
authRoot();
assumeTrue(connector.isAuthorized());
/* Write a test secret to vault */
try {
boolean res = connector.writeSecret(SECRET_PATH + "/toRevoke", "secret content");
assumeThat("Secret could not be written path.", res, is(true));
} catch (VaultConnectorException e) {
fail("Secret written to inaccessible path.");
}
SecretResponse res = null;
try {
res = connector.readSecret(SECRET_PATH + "/toRevoke");
} catch (VaultConnectorException e) {
fail("Written secret could not be read.");
}
assumeThat(res, is(notNullValue()));
/* Revoke secret by lease id */
try {
boolean revoked = connector.revoke(SECRET_PATH + "/toRevoke");
assertThat("Revocation of secret faiked.", revoked, is(true));
} catch (VaultConnectorException e) {
fail("Revocation threw unexpected exception.");
}
try {
connector.readSecret(SECRET_PATH + "/toRevoke");
fail("Revoked secret could still be read");
} catch (VaultConnectorException e) {
assertThat(e, is(notNullValue()));
}
}
/** /**
* Initialize Vault with resource datastore and generated configuration. * Initialize Vault with resource datastore and generated configuration.
* @return Vault Configuration * @return Vault Configuration