3 Commits

Author SHA1 Message Date
0b26946497 test: update equalsverifier to 4.1
All checks were successful
CI / build (17) (push) Successful in 33s
CI / build (true, 21) (push) Successful in 33s
2025-09-06 13:08:39 +02:00
0ff41f1ecc add java.io.Serial annotations to serialVersionUID fields 2025-09-06 13:08:37 +02:00
84a61f33ae require Java 17 or later (#100) 2025-09-06 13:08:35 +02:00
58 changed files with 1229 additions and 1390 deletions

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
jdk: [ 11, 17, 21 ]
jdk: [ 17, 21 ]
vault: [ '1.2.0', '1.20.0' ]
include:
- jdk: 21

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
jdk: [ 11, 17, 21 ]
jdk: [ 17, 21 ]
include:
- jdk: 21
analysis: true

View File

@@ -11,6 +11,9 @@
## 1.5.2 (2025-07-16)
### Breaking
* Requires Java 17 or later (#100)
### Dependencies
* Updated Jackson to 2.19.1 (#101)

View File

@@ -109,11 +109,11 @@ Token token = Token.builder()
.withDisplayName("new test token")
.withPolicies("pol1", "pol2")
.build();
vault.token().create(token);
vault.createToken(token);
// Create AppRole credentials
vault.appRole().create("testrole", policyList);
AppRoleSecretResponse secret = vault.appRole().createSecret("testrole");
vault.createAppRole("testrole", policyList);
AppRoleSecretResponse secret = vault.createAppRoleSecret("testrole");
```
## Links

View File

@@ -90,7 +90,7 @@
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>3.19.4</version>
<version>4.1</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -109,7 +109,7 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<configuration>
<release>11</release>
<release>17</release>
</configuration>
</plugin>
<plugin>
@@ -200,7 +200,7 @@
<version>[3.6.3,)</version>
</requireMavenVersion>
<requireJavaVersion>
<version>[11,)</version>
<version>[17,)</version>
</requireJavaVersion>
</rules>
</configuration>
@@ -246,7 +246,7 @@
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.11.3</version>
<configuration>
<source>11</source>
<source>17</source>
</configuration>
<executions>
<execution>

View File

@@ -1,217 +0,0 @@
/*
* Copyright 2016-2025 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;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import de.stklcode.jvault.connector.model.AppRole;
import de.stklcode.jvault.connector.model.AppRoleSecret;
import de.stklcode.jvault.connector.model.Token;
import de.stklcode.jvault.connector.model.TokenRole;
import de.stklcode.jvault.connector.model.response.*;
import java.util.ArrayList;
import java.util.List;
/**
* AppRole client interface.
* Provides methods to interact with Vault's AppRole API.
*
* @since 2.0.0 extracted from {@link VaultConnector}
*/
public interface AppRoleClient {
/**
* Register a new AppRole role from given metamodel.
*
* @param role The role
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean create(final AppRole role) throws VaultConnectorException;
/**
* Register new AppRole role with default policy.
*
* @param roleName The role name
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean create(final String roleName) throws VaultConnectorException {
return create(roleName, new ArrayList<>());
}
/**
* Register new AppRole role with policies.
*
* @param roleName The role name
* @param policies The policies to associate with
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean create(final String roleName, final List<String> policies) throws VaultConnectorException {
return create(roleName, policies, null);
}
/**
* Register new AppRole role with default policy and custom ID.
*
* @param roleName The role name
* @param roleID A custom role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean create(final String roleName, final String roleID) throws VaultConnectorException {
return create(roleName, new ArrayList<>(), roleID);
}
/**
* Register new AppRole role with policies and custom ID.
*
* @param roleName The role name
* @param policies The policies to associate with
* @param roleID A custom role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean create(final String roleName, final List<String> policies, final String roleID)
throws VaultConnectorException {
return create(AppRole.builder(roleName).withTokenPolicies(policies).withId(roleID).build());
}
/**
* Delete AppRole role from Vault.
*
* @param roleName The role name
* @return {@code true} on success
* @throws VaultConnectorException on error
*/
boolean delete(final String roleName) throws VaultConnectorException;
/**
* Lookup an AppRole role.
*
* @param roleName The role name
* @return Result of the lookup
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleResponse lookup(final String roleName) throws VaultConnectorException;
/**
* Retrieve ID for an AppRole role.
*
* @param roleName The role name
* @return The role ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
String getRoleID(final String roleName) throws VaultConnectorException;
/**
* Set custom ID for an AppRole role.
*
* @param roleName The role name
* @param roleID The role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean setRoleID(final String roleName, final String roleID) throws VaultConnectorException;
/**
* Register new random generated AppRole secret.
*
* @param roleName The role name
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default AppRoleSecretResponse createSecret(final String roleName) throws VaultConnectorException {
return createSecret(roleName, new AppRoleSecret());
}
/**
* Register new AppRole secret with custom ID.
*
* @param roleName The role name
* @param secretID A custom secret ID
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default AppRoleSecretResponse createSecret(final String roleName, final String secretID)
throws VaultConnectorException {
return createSecret(roleName, new AppRoleSecret(secretID));
}
/**
* Register new AppRole secret with custom ID.
*
* @param roleName The role name
* @param secret The secret meta object
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleSecretResponse createSecret(final String roleName, final AppRoleSecret secret)
throws VaultConnectorException;
/**
* Lookup an AppRole secret.
*
* @param roleName The role name
* @param secretID The secret ID
* @return Result of the lookup
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleSecretResponse lookupSecret(final String roleName, final String secretID)
throws VaultConnectorException;
/**
* Destroy an AppRole secret.
*
* @param roleName The role name
* @param secretID The secret meta object
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean destroySecret(final String roleName, final String secretID) throws VaultConnectorException;
/**
* List existing (accessible) AppRole roles.
*
* @return List of roles
* @throws VaultConnectorException on error
*/
List<String> listRoles() throws VaultConnectorException;
/**
* List existing (accessible) secret IDs for AppRole role.
*
* @param roleName The role name
* @return List of roles
* @throws VaultConnectorException on error
*/
List<String> listSecrets(final String roleName) throws VaultConnectorException;
}

View File

@@ -106,11 +106,55 @@ public class HTTPVaultConnector implements VaultConnector {
authorized = false;
}
@Override
public final SealResponse sealStatus() throws VaultConnectorException {
return request.get(SYS_SEAL_STATUS, emptyMap(), token, SealResponse.class);
}
@Override
public final void seal() throws VaultConnectorException {
request.put(SYS_SEAL, emptyMap(), token);
}
@Override
public final SealResponse unseal(final String key, final Boolean reset) throws VaultConnectorException {
Map<String, String> param = mapOfStrings(
"key", key,
"reset", reset
);
return request.put(SYS_UNSEAL, param, token, SealResponse.class);
}
@Override
public HealthResponse getHealth() throws VaultConnectorException {
return request.get(
SYS_HEALTH,
// Force status code to be 200, so we don't need to modify the request sequence.
Map.of(
"standbycode", "200", // Default: 429.
"sealedcode", "200", // Default: 503.
"uninitcode", "200" // Default: 501.
),
token,
HealthResponse.class
);
}
@Override
public final boolean isAuthorized() {
return authorized && (tokenTTL == 0 || tokenTTL >= System.currentTimeMillis());
}
@Override
public final List<AuthBackend> getAuthBackends() throws VaultConnectorException {
/* Issue request and parse response */
AuthMethodsResponse amr = request.get(SYS_AUTH, emptyMap(), token, AuthMethodsResponse.class);
return amr.getSupportedMethods().values().stream().map(AuthMethod::getType).collect(Collectors.toList());
}
@Override
public final TokenResponse authToken(final String token) throws VaultConnectorException {
/* set token */
@@ -158,6 +202,142 @@ public class HTTPVaultConnector implements VaultConnector {
return auth;
}
@Override
public final boolean createAppRole(final AppRole role) throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(String.format(AUTH_APPROLE_ROLE, role.getName(), ""), role, token);
/* Set custom ID if provided */
return !(role.getId() != null && !role.getId().isEmpty()) || setAppRoleID(role.getName(), role.getId());
}
@Override
public final AppRoleResponse lookupAppRole(final String roleName) throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse Secret */
return request.get(
String.format(AUTH_APPROLE_ROLE, roleName, ""),
emptyMap(),
token,
AppRoleResponse.class
);
}
@Override
public final boolean deleteAppRole(final String roleName) throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.deleteWithoutResponse(String.format(AUTH_APPROLE_ROLE, roleName, ""), token);
return true;
}
@Override
public final String getAppRoleID(final String roleName) throws VaultConnectorException {
requireAuth();
/* Issue request, parse response and extract Role ID */
return request.get(
String.format(AUTH_APPROLE_ROLE, roleName, "/role-id"),
emptyMap(),
token,
RawDataResponse.class
).getData().get("role_id").toString();
}
@Override
public final boolean setAppRoleID(final String roleName, final String roleID) throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
String.format(AUTH_APPROLE_ROLE, roleName, "/role-id"),
singletonMap("role_id", roleID),
token
);
return true;
}
@Override
public final AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret)
throws VaultConnectorException {
requireAuth();
if (secret.getId() != null && !secret.getId().isEmpty()) {
return request.post(
String.format(AUTH_APPROLE_ROLE, roleName, "/custom-secret-id"),
secret,
token,
AppRoleSecretResponse.class
);
} else {
return request.post(
String.format(AUTH_APPROLE_ROLE, roleName, "/secret-id"),
secret, token,
AppRoleSecretResponse.class
);
}
}
@Override
public final AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException {
requireAuth();
/* Issue request and parse secret response */
return request.post(
String.format(AUTH_APPROLE_ROLE, roleName, "/secret-id/lookup"),
new AppRoleSecret(secretID),
token,
AppRoleSecretResponse.class
);
}
@Override
public final boolean destroyAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
String.format(AUTH_APPROLE_ROLE, roleName, "/secret-id/destroy"),
new AppRoleSecret(secretID),
token);
return true;
}
@Override
public final List<String> listAppRoles() throws VaultConnectorException {
requireAuth();
SecretListResponse secrets = request.get(
AUTH_APPROLE + "/role?list=true",
emptyMap(),
token,
SecretListResponse.class
);
return secrets.getKeys();
}
@Override
public final List<String> listAppRoleSecrets(final String roleName) throws VaultConnectorException {
requireAuth();
SecretListResponse secrets = request.get(
String.format(AUTH_APPROLE_ROLE, roleName, "/secret-id?list=true"),
emptyMap(),
token,
SecretListResponse.class
);
return secrets.getKeys();
}
@Override
public final SecretResponse read(final String key) throws VaultConnectorException {
requireAuth();
@@ -165,6 +345,66 @@ public class HTTPVaultConnector implements VaultConnector {
return request.get(key, emptyMap(), token, PlainSecretResponse.class);
}
@Override
public final SecretResponse readSecretVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse secret metadata */
Map<String, String> args = mapOfStrings("version", version);
return request.get(mount + SECRET_DATA + key, args, token, MetaSecretResponse.class);
}
@Override
public final MetadataResponse readSecretMetadata(final String mount, final String key)
throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse secret metadata */
return request.get(mount + SECRET_METADATA + key, emptyMap(), token, MetadataResponse.class);
}
@Override
public void updateSecretMetadata(final String mount,
final String key,
final Integer maxVersions,
final boolean casRequired) throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = mapOf(
"max_versions", maxVersions,
"cas_required", casRequired
);
write(mount + SECRET_METADATA + key, payload);
}
@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 = mapOf("cas", cas);
/* Issue request and parse metadata response */
return request.post(
mount + SECRET_DATA + key,
Map.of(
"data", data,
"options", options
),
token,
SecretVersionResponse.class
);
}
@Override
public final List<String> list(final String path) throws VaultConnectorException {
requireAuth();
@@ -206,6 +446,57 @@ public class HTTPVaultConnector implements VaultConnector {
request.deleteWithoutResponse(key, token);
}
@Override
public final void deleteLatestSecretVersion(final String mount, final String key) throws VaultConnectorException {
delete(mount + SECRET_DATA + key);
}
@Override
public final void deleteAllSecretVersions(final String mount, final String key) throws VaultConnectorException {
delete(mount + SECRET_METADATA + key);
}
@Override
public final void deleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
handleSecretVersions(mount, SECRET_DELETE, key, versions);
}
@Override
public final void undeleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
handleSecretVersions(mount, SECRET_UNDELETE, key, versions);
}
@Override
public final void destroySecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
handleSecretVersions(mount, SECRET_DESTROY, key, versions);
}
/**
* Common method to bundle secret version operations.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param pathPart Path part to query.
* @param key Secret key.
* @param versions Versions to handle.
* @throws VaultConnectorException on error
* @since 0.8
*/
private void handleSecretVersions(final String mount,
final String pathPart,
final String key,
final int... versions) throws VaultConnectorException {
requireAuth();
/* Request HTTP response and expect empty result */
Map<String, Object> payload = singletonMap("versions", versions);
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(mount + pathPart + key, payload, token);
}
@Override
public final void revoke(final String leaseID) throws VaultConnectorException {
requireAuth();
@@ -228,28 +519,21 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
public KV2ClientImpl kv2() {
return new KV2ClientImpl();
public final AuthResponse createToken(final Token token) throws VaultConnectorException {
return createTokenInternal(token, AUTH_TOKEN + TOKEN_CREATE);
}
@Override
public TokenClientImpl token() {
return new TokenClientImpl();
public final AuthResponse createToken(final Token token, final boolean orphan) throws VaultConnectorException {
return createTokenInternal(token, AUTH_TOKEN + TOKEN_CREATE_ORPHAN);
}
@Override
public AppRoleClient appRole() {
return new AppRoleClientImpl();
}
@Override
public TransitClientImpl transit() {
return new TransitClientImpl();
}
@Override
public SysClientImpl sys() {
return new SysClientImpl();
public final AuthResponse createToken(final Token token, final String role) throws VaultConnectorException {
if (role == null || role.isEmpty()) {
throw new InvalidRequestException("No role name specified.");
}
return createTokenInternal(token, AUTH_TOKEN + TOKEN_CREATE + "/" + role);
}
@Override
@@ -259,6 +543,124 @@ public class HTTPVaultConnector implements VaultConnector {
tokenTTL = 0;
}
/**
* Create token.
* Centralized method to handle different token creation requests.
*
* @param token the token
* @param path request path
* @return the response
* @throws VaultConnectorException on error
*/
private AuthResponse createTokenInternal(final Token token, final String path) throws VaultConnectorException {
requireAuth();
if (token == null) {
throw new InvalidRequestException("Token must be provided.");
}
return request.post(path, token, this.token, AuthResponse.class);
}
@Override
public final TokenResponse lookupToken(final String token) throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse Secret */
return request.get(
AUTH_TOKEN + TOKEN_LOOKUP,
singletonMap("token", token),
token,
TokenResponse.class
);
}
@Override
public boolean createOrUpdateTokenRole(final String name, final TokenRole role) throws VaultConnectorException {
requireAuth();
if (name == null) {
throw new InvalidRequestException("Role name must be provided.");
} else if (role == null) {
throw new InvalidRequestException("Role must be provided.");
}
// Issue request and expect code 204 with empty response.
request.postWithoutResponse(AUTH_TOKEN + TOKEN_ROLES + "/" + name, role, token);
return true;
}
@Override
public TokenRoleResponse readTokenRole(final String name) throws VaultConnectorException {
requireAuth();
// Request HTTP response and parse response.
return request.get(AUTH_TOKEN + TOKEN_ROLES + "/" + name, emptyMap(), token, TokenRoleResponse.class);
}
@Override
public List<String> listTokenRoles() throws VaultConnectorException {
requireAuth();
return list(AUTH_TOKEN + TOKEN_ROLES);
}
@Override
public boolean deleteTokenRole(final String name) throws VaultConnectorException {
requireAuth();
if (name == null) {
throw new InvalidRequestException("Role name must be provided.");
}
// Issue request and expect code 204 with empty response.
request.deleteWithoutResponse(AUTH_TOKEN + TOKEN_ROLES + "/" + name, token);
return true;
}
@Override
public final TransitResponse transitEncrypt(final String keyName, final String plaintext)
throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = mapOf(
"plaintext", plaintext
);
return request.post(TRANSIT_ENCRYPT + keyName, payload, token, TransitResponse.class);
}
@Override
public final TransitResponse transitDecrypt(final String keyName, final String ciphertext)
throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = mapOf(
"ciphertext", ciphertext
);
return request.post(TRANSIT_DECRYPT + keyName, payload, token, TransitResponse.class);
}
@Override
public final TransitResponse transitHash(final String algorithm, final String input, final String format)
throws VaultConnectorException {
if (format != null && !"hex".equals(format) && !"base64".equals(format)) {
throw new IllegalArgumentException("Unsupported format " + format);
}
requireAuth();
Map<String, Object> payload = mapOf(
"input", input,
"format", format
);
return request.post(TRANSIT_HASH + algorithm, payload, token, TransitResponse.class);
}
/**
* Check for required authorization.
*
@@ -308,459 +710,4 @@ public class HTTPVaultConnector implements VaultConnector {
return map;
}
/**
* Sub-client for KV v2 methods.
*/
public class KV2ClientImpl implements KV2Client {
@Override
public final SecretResponse readVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse secret metadata */
Map<String, String> args = mapOfStrings("version", version);
return request.get(mount + SECRET_DATA + key, args, token, MetaSecretResponse.class);
}
@Override
public final MetadataResponse readMetadata(final String mount, final String key)
throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse secret metadata */
return request.get(mount + SECRET_METADATA + key, emptyMap(), token, MetadataResponse.class);
}
@Override
public void updateMetadata(final String mount,
final String key,
final Integer maxVersions,
final boolean casRequired) throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = mapOf(
"max_versions", maxVersions,
"cas_required", casRequired
);
write(mount + SECRET_METADATA + key, payload);
}
@Override
public final SecretVersionResponse writeData(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 = mapOf("cas", cas);
/* Issue request and parse metadata response */
return request.post(
mount + SECRET_DATA + key,
Map.of(
"data", data,
"options", options
),
token,
SecretVersionResponse.class
);
}
@Override
public final void deleteLatestVersion(final String mount, final String key) throws VaultConnectorException {
delete(mount + SECRET_DATA + key);
}
@Override
public final void deleteAllVersions(final String mount, final String key) throws VaultConnectorException {
delete(mount + SECRET_METADATA + key);
}
@Override
public final void deleteVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
handleSecretVersions(mount, SECRET_DELETE, key, versions);
}
@Override
public final void undeleteVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
handleSecretVersions(mount, SECRET_UNDELETE, key, versions);
}
@Override
public final void destroyVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
handleSecretVersions(mount, SECRET_DESTROY, key, versions);
}
/**
* Common method to bundle secret version operations.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param pathPart Path part to query.
* @param key Secret key.
* @param versions Versions to handle.
* @throws VaultConnectorException on error
* @since 0.8
*/
private void handleSecretVersions(final String mount,
final String pathPart,
final String key,
final int... versions) throws VaultConnectorException {
requireAuth();
/* Request HTTP response and expect empty result */
Map<String, Object> payload = singletonMap("versions", versions);
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(mount + pathPart + key, payload, token);
}
}
/**
* Sub-client for token methods.
*/
public class TokenClientImpl implements TokenClient {
@Override
public final AuthResponse create(final Token token) throws VaultConnectorException {
return createInternal(token, AUTH_TOKEN + TOKEN_CREATE);
}
@Override
public final AuthResponse create(final Token token, final boolean orphan) throws VaultConnectorException {
return createInternal(token, AUTH_TOKEN + TOKEN_CREATE_ORPHAN);
}
@Override
public final AuthResponse create(final Token token, final String role) throws VaultConnectorException {
if (role == null || role.isEmpty()) {
throw new InvalidRequestException("No role name specified.");
}
return createInternal(token, AUTH_TOKEN + TOKEN_CREATE + "/" + role);
}
/**
* Create token.
* Centralized method to handle different token creation requests.
*
* @param token the token
* @param path request path
* @return the response
* @throws VaultConnectorException on error
*/
private AuthResponse createInternal(final Token token, final String path) throws VaultConnectorException {
requireAuth();
if (token == null) {
throw new InvalidRequestException("Token must be provided.");
}
return request.post(path, token, HTTPVaultConnector.this.token, AuthResponse.class);
}
@Override
public final TokenResponse lookup(final String token) throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse Secret */
return request.get(
AUTH_TOKEN + TOKEN_LOOKUP,
singletonMap("token", token),
token,
TokenResponse.class
);
}
@Override
public boolean createOrUpdateRole(final String name, final TokenRole role) throws VaultConnectorException {
requireAuth();
if (name == null) {
throw new InvalidRequestException("Role name must be provided.");
} else if (role == null) {
throw new InvalidRequestException("Role must be provided.");
}
// Issue request and expect code 204 with empty response.
request.postWithoutResponse(AUTH_TOKEN + TOKEN_ROLES + "/" + name, role, token);
return true;
}
@Override
public TokenRoleResponse readRole(final String name) throws VaultConnectorException {
requireAuth();
// Request HTTP response and parse response.
return request.get(AUTH_TOKEN + TOKEN_ROLES + "/" + name, emptyMap(), token, TokenRoleResponse.class);
}
@Override
public List<String> listRoles() throws VaultConnectorException {
requireAuth();
return list(AUTH_TOKEN + TOKEN_ROLES);
}
@Override
public boolean deleteRole(final String name) throws VaultConnectorException {
requireAuth();
if (name == null) {
throw new InvalidRequestException("Role name must be provided.");
}
// Issue request and expect code 204 with empty response.
request.deleteWithoutResponse(AUTH_TOKEN + TOKEN_ROLES + "/" + name, token);
return true;
}
}
/**
* Sub-client for AppRole methods.
*/
public class AppRoleClientImpl implements AppRoleClient {
@Override
public final boolean create(final AppRole role) throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(String.format(AUTH_APPROLE_ROLE, role.getName(), ""), role, token);
/* Set custom ID if provided */
return !(role.getId() != null && !role.getId().isEmpty()) || setRoleID(role.getName(), role.getId());
}
@Override
public final AppRoleResponse lookup(final String roleName) throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse Secret */
return request.get(
String.format(AUTH_APPROLE_ROLE, roleName, ""),
emptyMap(),
token,
AppRoleResponse.class
);
}
@Override
public final boolean delete(final String roleName) throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.deleteWithoutResponse(String.format(AUTH_APPROLE_ROLE, roleName, ""), token);
return true;
}
@Override
public final String getRoleID(final String roleName) throws VaultConnectorException {
requireAuth();
/* Issue request, parse response and extract Role ID */
return request.get(
String.format(AUTH_APPROLE_ROLE, roleName, "/role-id"),
emptyMap(),
token,
RawDataResponse.class
).getData().get("role_id").toString();
}
@Override
public final boolean setRoleID(final String roleName, final String roleID) throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
String.format(AUTH_APPROLE_ROLE, roleName, "/role-id"),
singletonMap("role_id", roleID),
token
);
return true;
}
@Override
public final AppRoleSecretResponse createSecret(final String roleName, final AppRoleSecret secret)
throws VaultConnectorException {
requireAuth();
if (secret.getId() != null && !secret.getId().isEmpty()) {
return request.post(
String.format(AUTH_APPROLE_ROLE, roleName, "/custom-secret-id"),
secret,
token,
AppRoleSecretResponse.class
);
} else {
return request.post(
String.format(AUTH_APPROLE_ROLE, roleName, "/secret-id"),
secret, token,
AppRoleSecretResponse.class
);
}
}
@Override
public final AppRoleSecretResponse lookupSecret(final String roleName, final String secretID)
throws VaultConnectorException {
requireAuth();
/* Issue request and parse secret response */
return request.post(
String.format(AUTH_APPROLE_ROLE, roleName, "/secret-id/lookup"),
new AppRoleSecret(secretID),
token,
AppRoleSecretResponse.class
);
}
@Override
public final boolean destroySecret(final String roleName, final String secretID)
throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
String.format(AUTH_APPROLE_ROLE, roleName, "/secret-id/destroy"),
new AppRoleSecret(secretID),
token);
return true;
}
@Override
public final List<String> listRoles() throws VaultConnectorException {
requireAuth();
SecretListResponse secrets = request.get(
AUTH_APPROLE + "/role?list=true",
emptyMap(),
token,
SecretListResponse.class
);
return secrets.getKeys();
}
@Override
public final List<String> listSecrets(final String roleName) throws VaultConnectorException {
requireAuth();
SecretListResponse secrets = request.get(
String.format(AUTH_APPROLE_ROLE, roleName, "/secret-id?list=true"),
emptyMap(),
token,
SecretListResponse.class
);
return secrets.getKeys();
}
}
/**
* Sub-client for transit methods.
*/
public class TransitClientImpl implements TransitClient {
@Override
public final TransitResponse encrypt(final String keyName, final String plaintext)
throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = mapOf(
"plaintext", plaintext
);
return request.post(TRANSIT_ENCRYPT + keyName, payload, token, TransitResponse.class);
}
@Override
public final TransitResponse decrypt(final String keyName, final String ciphertext)
throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = mapOf(
"ciphertext", ciphertext
);
return request.post(TRANSIT_DECRYPT + keyName, payload, token, TransitResponse.class);
}
@Override
public final TransitResponse hash(final String algorithm, final String input, final String format)
throws VaultConnectorException {
if (format != null && !"hex".equals(format) && !"base64".equals(format)) {
throw new IllegalArgumentException("Unsupported format " + format);
}
requireAuth();
Map<String, Object> payload = mapOf(
"input", input,
"format", format
);
return request.post(TRANSIT_HASH + algorithm, payload, token, TransitResponse.class);
}
}
/**
* Sub-client for system methods.
*/
public class SysClientImpl implements SysClient {
@Override
public final SealResponse sealStatus() throws VaultConnectorException {
return request.get(SYS_SEAL_STATUS, emptyMap(), token, SealResponse.class);
}
@Override
public final void seal() throws VaultConnectorException {
request.put(SYS_SEAL, emptyMap(), token);
}
@Override
public final SealResponse unseal(final String key, final Boolean reset) throws VaultConnectorException {
Map<String, String> param = mapOfStrings(
"key", key,
"reset", reset
);
return request.put(SYS_UNSEAL, param, token, SealResponse.class);
}
@Override
public HealthResponse getHealth() throws VaultConnectorException {
return request.get(
SYS_HEALTH,
// Force status code to be 200, so we don't need to modify the request sequence.
Map.of(
"standbycode", "200", // Default: 429.
"sealedcode", "200", // Default: 503.
"uninitcode", "200" // Default: 501.
),
token,
HealthResponse.class
);
}
@Override
public final List<AuthBackend> getAuthBackends() throws VaultConnectorException {
/* Issue request and parse response */
AuthMethodsResponse amr = request.get(SYS_AUTH, emptyMap(), token, AuthMethodsResponse.class);
return amr.getSupportedMethods().values().stream().map(AuthMethod::getType).collect(Collectors.toList());
}
}
}

View File

@@ -1,200 +0,0 @@
/*
* Copyright 2016-2025 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;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import de.stklcode.jvault.connector.model.response.MetadataResponse;
import de.stklcode.jvault.connector.model.response.SecretResponse;
import de.stklcode.jvault.connector.model.response.SecretVersionResponse;
import java.util.Map;
/**
* KV v2 client interface.
* Provides methods to interact with Vault's KV v2 API.
*
* @since 2.0.0 extracted from {@link VaultConnector}
*/
public interface KV2Client {
/**
* Retrieve the latest secret data for specific version from Vault.
* <br>
* Path {@code <mount>/data/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @return Secret response
* @throws VaultConnectorException on error
* @since 0.8
*/
default SecretResponse readData(final String mount, final String key) throws VaultConnectorException {
return readVersion(mount, key, null);
}
/**
* Write secret to Vault.
* <br>
* Path {@code <mount>/data/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (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 writeData(final String mount,
final String key,
final Map<String, Object> data) throws VaultConnectorException {
return writeData(mount, key, data, null);
}
/**
* Write secret to Vault.
* <br>
* Path {@code <mount>/data/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (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 writeData(final String mount,
final String key,
final Map<String, Object> data,
final Integer cas) throws VaultConnectorException;
/**
* Retrieve secret data from Vault.
* <br>
* Path {@code <mount>/data/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (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.
* @throws VaultConnectorException on error
* @since 0.8
*/
SecretResponse readVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException;
/**
* Retrieve secret metadata from Vault.
* <br>
* Path {@code <mount>/metadata/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @return Metadata response
* @throws VaultConnectorException on error
* @since 0.8
*/
MetadataResponse readMetadata(final String mount, final String key) throws VaultConnectorException;
/**
* Update secret metadata.
* <br>
* Path {@code <mount>/metadata/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param maxVersions Maximum number of versions (fallback to backend default if {@code null})
* @param casRequired Specify if Check-And-Set is required for this secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
void updateMetadata(final String mount,
final String key,
final Integer maxVersions,
final boolean casRequired) throws VaultConnectorException;
/**
* Delete latest version of a secret from Vault.
* <br>
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteLatestVersion(final String mount, final String key) throws VaultConnectorException;
/**
* Delete latest version of a secret from Vault.
* <br>
* Prefix {@code secret/} is automatically added to path.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteAllVersions(final String mount, final String key) throws VaultConnectorException;
/**
* Delete secret versions from Vault.
* <br>
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to delete.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Undelete (restore) secret versions from Vault.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to undelete.
* @throws VaultConnectorException on error
* @since 0.8
*/
void undeleteVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Destroy secret versions from Vault.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to destroy.
* @throws VaultConnectorException on error
* @since 0.8
*/
void destroyVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
}

View File

@@ -1,88 +0,0 @@
/*
* Copyright 2016-2025 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;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import de.stklcode.jvault.connector.model.AuthBackend;
import de.stklcode.jvault.connector.model.Token;
import de.stklcode.jvault.connector.model.TokenRole;
import de.stklcode.jvault.connector.model.response.*;
import java.util.List;
/**
* Sys client interface.
* Provides methods to interact with Vault's system API.
*
* @since 2.0.0 extracted from {@link VaultConnector}
*/
public interface SysClient {
/**
* Retrieve status of vault seal.
*
* @return Seal status
* @throws VaultConnectorException on error
*/
SealResponse sealStatus() throws VaultConnectorException;
/**
* Seal vault.
*
* @throws VaultConnectorException on error
*/
void seal() throws VaultConnectorException;
/**
* Unseal vault.
*
* @param key A single master share key
* @param reset Discard previously provided keys (optional)
* @return Response with seal status
* @throws VaultConnectorException on error
*/
SealResponse unseal(final String key, final Boolean reset) throws VaultConnectorException;
/**
* Unseal vault.
*
* @param key A single master share key
* @return Response with seal status
* @throws VaultConnectorException on error
*/
default SealResponse unseal(final String key) throws VaultConnectorException {
return unseal(key, null);
}
/**
* Query server health information.
*
* @return Health information.
* @throws VaultConnectorException on error
* @since 0.7.0
*/
HealthResponse getHealth() throws VaultConnectorException;
/**
* Get all available authentication backends.
*
* @return List of backends
* @throws VaultConnectorException on error
*/
List<AuthBackend> getAuthBackends() throws VaultConnectorException;
}

View File

@@ -1,125 +0,0 @@
/*
* Copyright 2016-2025 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;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import de.stklcode.jvault.connector.model.Token;
import de.stklcode.jvault.connector.model.TokenRole;
import de.stklcode.jvault.connector.model.response.AuthResponse;
import de.stklcode.jvault.connector.model.response.TokenResponse;
import de.stklcode.jvault.connector.model.response.TokenRoleResponse;
import java.util.List;
/**
* Token client interface.
* Provides methods to interact with Vault's token API.
*
* @since 2.0.0 extracted from {@link VaultConnector}
*/
public interface TokenClient {
/**
* Create a new token.
*
* @param token the token
* @return the result response
* @throws VaultConnectorException on error
*/
AuthResponse create(final Token token) throws VaultConnectorException;
/**
* Create a new token.
*
* @param token the token
* @param orphan create orphan token
* @return the result response
* @throws VaultConnectorException on error
*/
AuthResponse create(final Token token, boolean orphan) throws VaultConnectorException;
/**
* Create a new token for specific role.
*
* @param token the token
* @param role the role name
* @return the result response
* @throws VaultConnectorException on error
*/
AuthResponse create(final Token token, final String role) throws VaultConnectorException;
/**
* Lookup token information.
*
* @param token the token
* @return the result response
* @throws VaultConnectorException on error
*/
TokenResponse lookup(final String token) throws VaultConnectorException;
/**
* Create a new or update an existing token role.
*
* @param role the role entity (name must be set)
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
default boolean createOrUpdateRole(final TokenRole role) throws VaultConnectorException {
return createOrUpdateRole(role.getName(), role);
}
/**
* Create a new or update an existing token role.
*
* @param name the role name (overrides name possibly set in role entity)
* @param role the role entity
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
boolean createOrUpdateRole(final String name, final TokenRole role) throws VaultConnectorException;
/**
* Lookup token information.
*
* @param name the role name
* @return the result response
* @throws VaultConnectorException on error
* @since 0.9
*/
TokenRoleResponse readRole(final String name) throws VaultConnectorException;
/**
* List available token roles from Vault.
*
* @return List of token roles
* @throws VaultConnectorException on error
* @since 0.9
*/
List<String> listRoles() throws VaultConnectorException;
/**
* Delete a token role.
*
* @param name the role name to delete
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
boolean deleteRole(final String name) throws VaultConnectorException;
}

View File

@@ -1,107 +0,0 @@
/*
* Copyright 2016-2025 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;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import de.stklcode.jvault.connector.model.response.TransitResponse;
import java.util.Base64;
/**
* Transit client interface.
* Provides methods to interact with Vault's transit API.
*
* @since 2.0.0 extracted from {@link VaultConnector}
*/
public interface TransitClient {
/**
* Encrypt plaintext via transit engine from Vault.
*
* @param keyName Transit key name
* @param plaintext Text to encrypt (Base64 encoded)
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse encrypt(final String keyName, final String plaintext) throws VaultConnectorException;
/**
* Encrypt plaintext via transit engine from Vault.
*
* @param keyName Transit key name
* @param plaintext Binary data to encrypt
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse encrypt(final String keyName, final byte[] plaintext)
throws VaultConnectorException {
return encrypt(keyName, Base64.getEncoder().encodeToString(plaintext));
}
/**
* Decrypt ciphertext via transit engine from Vault.
*
* @param keyName Transit key name
* @param ciphertext Text to decrypt
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse decrypt(final String keyName, final String ciphertext) throws VaultConnectorException;
/**
* Hash data in hex format via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse hash(final String algorithm, final String input) throws VaultConnectorException {
return hash(algorithm, input, "hex");
}
/**
* Hash data via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash (Base64 encoded)
* @param format Specifies the output encoding (hex/base64)
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse hash(final String algorithm, final String input, final String format)
throws VaultConnectorException;
/**
* Hash data via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse hash(final String algorithm, final byte[] input, final String format)
throws VaultConnectorException {
return hash(algorithm, Base64.getEncoder().encodeToString(input), format);
}
}

View File

@@ -37,6 +37,59 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
void resetAuth();
/**
* Retrieve status of vault seal.
*
* @return Seal status
* @throws VaultConnectorException on error
*/
SealResponse sealStatus() throws VaultConnectorException;
/**
* Seal vault.
*
* @throws VaultConnectorException on error
*/
void seal() throws VaultConnectorException;
/**
* Unseal vault.
*
* @param key A single master share key
* @param reset Discard previously provided keys (optional)
* @return Response with seal status
* @throws VaultConnectorException on error
*/
SealResponse unseal(final String key, final Boolean reset) throws VaultConnectorException;
/**
* Unseal vault.
*
* @param key A single master share key
* @return Response with seal status
* @throws VaultConnectorException on error
*/
default SealResponse unseal(final String key) throws VaultConnectorException {
return unseal(key, null);
}
/**
* Query server health information.
*
* @return Health information.
* @throws VaultConnectorException on error
* @since 0.7.0
*/
HealthResponse getHealth() throws VaultConnectorException;
/**
* Get all available authentication backends.
*
* @return List of backends
* @throws VaultConnectorException on error
*/
List<AuthBackend> getAuthBackends() throws VaultConnectorException;
/**
* Authorize to Vault using token.
*
@@ -79,6 +132,187 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
AuthResponse authAppRole(final String roleID, final String secretID) throws VaultConnectorException;
/**
* Register a new AppRole role from given metamodel.
*
* @param role The role
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean createAppRole(final AppRole role) throws VaultConnectorException;
/**
* Register new AppRole role with default policy.
*
* @param roleName The role name
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName) throws VaultConnectorException {
return createAppRole(roleName, new ArrayList<>());
}
/**
* Register new AppRole role with policies.
*
* @param roleName The role name
* @param policies The policies to associate with
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final List<String> policies) throws VaultConnectorException {
return createAppRole(roleName, policies, null);
}
/**
* Register new AppRole role with default policy and custom ID.
*
* @param roleName The role name
* @param roleID A custom role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final String roleID) throws VaultConnectorException {
return createAppRole(roleName, new ArrayList<>(), roleID);
}
/**
* Register new AppRole role with policies and custom ID.
*
* @param roleName The role name
* @param policies The policies to associate with
* @param roleID A custom role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final List<String> policies, final String roleID)
throws VaultConnectorException {
return createAppRole(AppRole.builder(roleName).withTokenPolicies(policies).withId(roleID).build());
}
/**
* Delete AppRole role from Vault.
*
* @param roleName The role name
* @return {@code true} on success
* @throws VaultConnectorException on error
*/
boolean deleteAppRole(final String roleName) throws VaultConnectorException;
/**
* Lookup an AppRole role.
*
* @param roleName The role name
* @return Result of the lookup
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleResponse lookupAppRole(final String roleName) throws VaultConnectorException;
/**
* Retrieve ID for an AppRole role.
*
* @param roleName The role name
* @return The role ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
String getAppRoleID(final String roleName) throws VaultConnectorException;
/**
* Set custom ID for an AppRole role.
*
* @param roleName The role name
* @param roleID The role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean setAppRoleID(final String roleName, final String roleID) throws VaultConnectorException;
/**
* Register new random generated AppRole secret.
*
* @param roleName The role name
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default AppRoleSecretResponse createAppRoleSecret(final String roleName) throws VaultConnectorException {
return createAppRoleSecret(roleName, new AppRoleSecret());
}
/**
* Register new AppRole secret with custom ID.
*
* @param roleName The role name
* @param secretID A custom secret ID
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default AppRoleSecretResponse createAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException {
return createAppRoleSecret(roleName, new AppRoleSecret(secretID));
}
/**
* Register new AppRole secret with custom ID.
*
* @param roleName The role name
* @param secret The secret meta object
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret)
throws VaultConnectorException;
/**
* Lookup an AppRole secret.
*
* @param roleName The role name
* @param secretID The secret ID
* @return Result of the lookup
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException;
/**
* Destroy an AppRole secret.
*
* @param roleName The role name
* @param secretID The secret meta object
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean destroyAppRoleSecret(final String roleName, final String secretID) throws VaultConnectorException;
/**
* List existing (accessible) AppRole roles.
*
* @return List of roles
* @throws VaultConnectorException on error
*/
List<String> listAppRoles() throws VaultConnectorException;
/**
* List existing (accessible) secret IDs for AppRole role.
*
* @param roleName The role name
* @return List of roles
* @throws VaultConnectorException on error
*/
List<String> listAppRoleSecrets(final String roleName) throws VaultConnectorException;
/**
* Get authorization status.
*
@@ -96,6 +330,108 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
SecretResponse read(final String key) throws VaultConnectorException;
/**
* Retrieve the latest secret data for specific version from Vault.
* <br>
* Path {@code <mount>/data/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @return Secret response
* @throws VaultConnectorException on error
* @since 0.8
*/
default SecretResponse readSecretData(final String mount, final String key) throws VaultConnectorException {
return readSecretVersion(mount, key, null);
}
/**
* Write secret to Vault.
* <br>
* Path {@code <mount>/data/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (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.
* <br>
* Path {@code <mount>/data/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (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.
* <br>
* Path {@code <mount>/data/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (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.
* @throws VaultConnectorException on error
* @since 0.8
*/
SecretResponse readSecretVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException;
/**
* Retrieve secret metadata from Vault.
* <br>
* Path {@code <mount>/metadata/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @return Metadata response
* @throws VaultConnectorException on error
* @since 0.8
*/
MetadataResponse readSecretMetadata(final String mount, final String key) throws VaultConnectorException;
/**
* Update secret metadata.
* <br>
* Path {@code <mount>/metadata/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param maxVersions Maximum number of versions (fallback to backend default if {@code null})
* @param casRequired Specify if Check-And-Set is required for this secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
void updateSecretMetadata(final String mount,
final String key,
final Integer maxVersions,
final boolean casRequired) throws VaultConnectorException;
/**
* List available nodes from Vault.
*
@@ -151,6 +487,71 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
void delete(final String key) throws VaultConnectorException;
/**
* Delete latest version of a secret from Vault.
* <br>
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteLatestSecretVersion(final String mount, final String key) throws VaultConnectorException;
/**
* Delete latest version of a secret from Vault.
* <br>
* Prefix {@code secret/} is automatically added to path.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteAllSecretVersions(final String mount, final String key) throws VaultConnectorException;
/**
* Delete secret versions from Vault.
* <br>
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to delete.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Undelete (restore) secret versions from Vault.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to undelete.
* @throws VaultConnectorException on error
* @since 0.8
*/
void undeleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Destroy secret versions from Vault.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to destroy.
* @throws VaultConnectorException on error
* @since 0.8
*/
void destroySecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Revoke given lease immediately.
*
@@ -181,44 +582,170 @@ public interface VaultConnector extends AutoCloseable, Serializable {
SecretResponse renew(final String leaseID, final Integer increment) throws VaultConnectorException;
/**
* Get client for KV v2 API.
* Create a new token.
*
* @return KV v2 client
* @since 2.0.0
* @param token the token
* @return the result response
* @throws VaultConnectorException on error
*/
KV2Client kv2();
AuthResponse createToken(final Token token) throws VaultConnectorException;
/**
* Get client for token API.
* Create a new token.
*
* @return Token client
* @since 2.0.0
* @param token the token
* @param orphan create orphan token
* @return the result response
* @throws VaultConnectorException on error
*/
TokenClient token();
AuthResponse createToken(final Token token, boolean orphan) throws VaultConnectorException;
/**
* Get client for AppRole API.
* Create a new token for specific role.
*
* @return AppRole client
* @since 2.0.0
* @param token the token
* @param role the role name
* @return the result response
* @throws VaultConnectorException on error
*/
AppRoleClient appRole();
AuthResponse createToken(final Token token, final String role) throws VaultConnectorException;
/**
* Get client for transit API.
* Lookup token information.
*
* @return Transit client
* @since 2.0.0
* @param token the token
* @return the result response
* @throws VaultConnectorException on error
*/
TransitClient transit();
TokenResponse lookupToken(final String token) throws VaultConnectorException;
/**
* Get client for system API.
* Create a new or update an existing token role.
*
* @return System client
* @since 2.0.0
* @param role the role entity (name must be set)
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
SysClient sys();
default boolean createOrUpdateTokenRole(final TokenRole role) throws VaultConnectorException {
return createOrUpdateTokenRole(role.getName(), role);
}
/**
* Create a new or update an existing token role.
*
* @param name the role name (overrides name possibly set in role entity)
* @param role the role entity
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
boolean createOrUpdateTokenRole(final String name, final TokenRole role) throws VaultConnectorException;
/**
* Lookup token information.
*
* @param name the role name
* @return the result response
* @throws VaultConnectorException on error
* @since 0.9
*/
TokenRoleResponse readTokenRole(final String name) throws VaultConnectorException;
/**
* List available token roles from Vault.
*
* @return List of token roles
* @throws VaultConnectorException on error
* @since 0.9
*/
List<String> listTokenRoles() throws VaultConnectorException;
/**
* Delete a token role.
*
* @param name the role name to delete
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
boolean deleteTokenRole(final String name) throws VaultConnectorException;
/**
* Encrypt plaintext via transit engine from Vault.
*
* @param keyName Transit key name
* @param plaintext Text to encrypt (Base64 encoded)
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse transitEncrypt(final String keyName, final String plaintext) throws VaultConnectorException;
/**
* Encrypt plaintext via transit engine from Vault.
*
* @param keyName Transit key name
* @param plaintext Binary data to encrypt
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse transitEncrypt(final String keyName, final byte[] plaintext)
throws VaultConnectorException {
return transitEncrypt(keyName, Base64.getEncoder().encodeToString(plaintext));
}
/**
* Decrypt ciphertext via transit engine from Vault.
*
* @param keyName Transit key name
* @param ciphertext Text to decrypt
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse transitDecrypt(final String keyName, final String ciphertext) throws VaultConnectorException;
/**
* Hash data in hex format via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse transitHash(final String algorithm, final String input) throws VaultConnectorException {
return transitHash(algorithm, input, "hex");
}
/**
* Hash data via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash (Base64 encoded)
* @param format Specifies the output encoding (hex/base64)
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse transitHash(final String algorithm, final String input, final String format)
throws VaultConnectorException;
/**
* Hash data via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse transitHash(final String algorithm, final byte[] input, final String format)
throws VaultConnectorException {
return transitHash(algorithm, Base64.getEncoder().encodeToString(input), format);
}
/**
* Read credentials for MySQL backend at default mount point.
@@ -289,5 +816,4 @@ public interface VaultConnector extends AutoCloseable, Serializable {
throws VaultConnectorException {
return (CredentialsResponse) read(mount + "/creds/" + role);
}
}

View File

@@ -16,6 +16,8 @@
package de.stklcode.jvault.connector.exception;
import java.io.Serial;
/**
* Exception thrown trying to do a request without any authorization handles.
*
@@ -23,5 +25,6 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public class AuthorizationRequiredException extends VaultConnectorException {
@Serial
private static final long serialVersionUID = 2629577936657393880L;
}

View File

@@ -16,6 +16,8 @@
package de.stklcode.jvault.connector.exception;
import java.io.Serial;
/**
* Exception thrown on problems with connection to Vault backend.
*
@@ -23,6 +25,7 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public class ConnectionException extends VaultConnectorException {
@Serial
private static final long serialVersionUID = 3005430116002990418L;
/**

View File

@@ -16,6 +16,8 @@
package de.stklcode.jvault.connector.exception;
import java.io.Serial;
/**
* Exception thrown when trying to send malformed request.
*
@@ -23,6 +25,7 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public class InvalidRequestException extends VaultConnectorException {
@Serial
private static final long serialVersionUID = -6712239648281809159L;
/**

View File

@@ -16,6 +16,8 @@
package de.stklcode.jvault.connector.exception;
import java.io.Serial;
/**
* Exception thrown when response from vault returned with erroneous status code or payload could not be parsed
* to entity class.
@@ -24,6 +26,7 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public final class InvalidResponseException extends VaultConnectorException {
@Serial
private static final long serialVersionUID = 2003151038614163479L;
private final Integer statusCode;

View File

@@ -16,6 +16,8 @@
package de.stklcode.jvault.connector.exception;
import java.io.Serial;
/**
* Exception thrown when trying to access a path the current user/token does not have permission to access.
*
@@ -23,6 +25,7 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public class PermissionDeniedException extends VaultConnectorException {
@Serial
private static final long serialVersionUID = -7149134015090750776L;
/**

View File

@@ -16,6 +16,8 @@
package de.stklcode.jvault.connector.exception;
import java.io.Serial;
/**
* Exception thrown on errors with TLS connection.
*
@@ -23,6 +25,7 @@ package de.stklcode.jvault.connector.exception;
* @since 0.4.0
*/
public class TlsException extends VaultConnectorException {
@Serial
private static final long serialVersionUID = -5139276834988258086L;
/**

View File

@@ -16,6 +16,8 @@
package de.stklcode.jvault.connector.exception;
import java.io.Serial;
/**
* Abstract Exception class for Vault Connector internal exceptions.
*
@@ -23,6 +25,7 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public abstract class VaultConnectorException extends Exception {
@Serial
private static final long serialVersionUID = -2612477894310906036L;
/**

View File

@@ -18,6 +18,8 @@ package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.annotation.*;
import java.io.Serial;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@@ -32,6 +34,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRole implements Serializable {
@Serial
private static final long serialVersionUID = 1546673231280751679L;
@JsonProperty("role_name")

View File

@@ -18,6 +18,7 @@ package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.annotation.*;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
@@ -32,6 +33,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleSecret implements Serializable {
@Serial
private static final long serialVersionUID = -3401074170145792641L;
@JsonProperty("secret_id")

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.util.*;
@@ -32,6 +33,7 @@ import java.util.*;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class Token implements Serializable {
@Serial
private static final long serialVersionUID = 7003016071684507115L;
@JsonProperty("id")

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@@ -34,6 +35,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenRole implements Serializable {
@Serial
private static final long serialVersionUID = -4856948364869438439L;
@JsonProperty("name")

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.AppRole;
import java.io.Serial;
import java.util.Objects;
/**
@@ -30,6 +31,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleResponse extends VaultDataResponse {
@Serial
private static final long serialVersionUID = -6536422219633829177L;
@JsonProperty("data")

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.AppRoleSecret;
import java.io.Serial;
import java.util.Objects;
/**
@@ -30,6 +31,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleSecretResponse extends VaultDataResponse {
@Serial
private static final long serialVersionUID = -2484103304072370585L;
@JsonProperty("data")

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
import java.io.Serial;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@@ -32,6 +33,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthMethodsResponse extends VaultDataResponse {
@Serial
private static final long serialVersionUID = -1802724129533405375L;
@JsonProperty("data")

View File

@@ -19,6 +19,8 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
import java.io.Serial;
/**
* Vault response for authentication providing auth info in {@link AuthData} field.
*
@@ -27,5 +29,6 @@ import de.stklcode.jvault.connector.model.response.embedded.AuthData;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthResponse extends VaultDataResponse {
@Serial
private static final long serialVersionUID = 1628851361067456715L;
}

View File

@@ -18,6 +18,8 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.io.Serial;
/**
* Vault response from credentials lookup. Simple wrapper for data objects containing username and password fields.
*
@@ -26,6 +28,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class CredentialsResponse extends PlainSecretResponse {
@Serial
private static final long serialVersionUID = -1439692963299045425L;
/**

View File

@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.util.List;
import java.util.Objects;
@@ -30,6 +31,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class ErrorResponse implements VaultResponse {
@Serial
private static final long serialVersionUID = -6227368087842549149L;
@JsonProperty("errors")

View File

@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.util.Objects;
/**
@@ -29,6 +30,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class HealthResponse implements VaultResponse {
@Serial
private static final long serialVersionUID = 8675155916902904516L;
@JsonProperty("cluster_id")

View File

@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.util.Objects;
/**
@@ -29,6 +30,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class HelpResponse implements VaultResponse {
@Serial
private static final long serialVersionUID = -1152070966642848490L;
@JsonProperty("help")

View File

@@ -21,6 +21,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.SecretWrapper;
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
import java.io.Serial;
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
@@ -34,6 +35,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class MetaSecretResponse extends SecretResponse {
@Serial
private static final long serialVersionUID = -1076542846391240162L;
@JsonProperty("data")

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.SecretMetadata;
import java.io.Serial;
import java.util.Objects;
@@ -31,6 +32,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class MetadataResponse extends VaultDataResponse {
@Serial
private static final long serialVersionUID = -3679762333630984679L;
@JsonProperty("data")

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
import java.io.Serial;
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
@@ -33,6 +34,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class PlainSecretResponse extends SecretResponse {
@Serial
private static final long serialVersionUID = 3010138542437913023L;
@JsonProperty("data")

View File

@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
@@ -31,6 +32,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class RawDataResponse extends VaultDataResponse {
@Serial
private static final long serialVersionUID = -319727427792124071L;
@JsonProperty("data")

View File

@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.time.ZonedDateTime;
import java.util.Objects;
@@ -30,6 +31,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class SealResponse implements VaultResponse {
@Serial
private static final long serialVersionUID = -6000309255473305787L;
@JsonProperty("type")

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.SecretListWrapper;
import java.io.Serial;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -32,8 +33,9 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class SecretListResponse extends VaultDataResponse {
@Serial
private static final long serialVersionUID = 8597121175002967213L;
@JsonProperty("data")
private SecretListWrapper data;

View File

@@ -25,6 +25,7 @@ import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
import java.io.IOException;
import java.io.Serial;
import java.io.Serializable;
import java.util.Map;
@@ -37,6 +38,7 @@ import java.util.Map;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class SecretResponse extends VaultDataResponse {
@Serial
private static final long serialVersionUID = 5198088815871692951L;
/**

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
import java.io.Serial;
import java.util.Objects;
/**
@@ -30,6 +31,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecretVersionResponse extends VaultDataResponse {
@Serial
private static final long serialVersionUID = 2748635005258576174L;
@JsonProperty("data")

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
import java.io.Serial;
import java.util.Objects;
/**
@@ -30,6 +31,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenResponse extends VaultDataResponse {
@Serial
private static final long serialVersionUID = -4341114947980033457L;
@JsonProperty("data")

View File

@@ -21,6 +21,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.TokenRole;
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
import java.io.Serial;
import java.util.Objects;
/**
@@ -31,6 +32,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenRoleResponse extends VaultDataResponse {
@Serial
private static final long serialVersionUID = 5265363857731948626L;
@JsonProperty("data")

View File

@@ -18,6 +18,7 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonSetter;
import java.io.Serial;
import java.util.Map;
import java.util.Objects;
@@ -29,6 +30,7 @@ import java.util.Objects;
*/
public class TransitResponse extends VaultDataResponse {
@Serial
private static final long serialVersionUID = 6873804240772242771L;
private String ciphertext;

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
import de.stklcode.jvault.connector.model.response.embedded.WrapInfo;
import java.io.Serial;
import java.util.List;
import java.util.Objects;
@@ -30,6 +31,7 @@ import java.util.Objects;
* @since 0.1
*/
public abstract class VaultDataResponse implements VaultResponse {
@Serial
private static final long serialVersionUID = 4787715235558510045L;
@JsonProperty("request_id")

View File

@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
@@ -33,6 +34,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthData implements Serializable {
@Serial
private static final long serialVersionUID = 5969334512309655317L;
@JsonProperty("client_token")

View File

@@ -21,6 +21,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import de.stklcode.jvault.connector.model.AuthBackend;
import java.io.Serial;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
@@ -34,6 +35,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthMethod implements Serializable {
@Serial
private static final long serialVersionUID = -439987082190917691L;
private AuthBackend type;

View File

@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
@@ -31,6 +32,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class MfaConstraintAny implements Serializable {
@Serial
private static final long serialVersionUID = 1226126781813149627L;
@JsonProperty("any")

View File

@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
@@ -30,6 +31,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class MfaMethodId implements Serializable {
@Serial
private static final long serialVersionUID = 691298070242998814L;
@JsonProperty("type")

View File

@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
@@ -31,6 +32,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class MfaRequirement implements Serializable {
@Serial
private static final long serialVersionUID = -2516941512455319638L;
@JsonProperty("mfa_request_id")

View File

@@ -3,6 +3,8 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
@@ -15,6 +17,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class MountConfig implements Serializable {
@Serial
private static final long serialVersionUID = 7241631159224756605L;
@JsonProperty("default_lease_ttl")

View File

@@ -3,6 +3,7 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
@@ -16,7 +17,9 @@ import java.util.Objects;
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecretListWrapper implements Serializable {
@Serial
private static final long serialVersionUID = -8777605197063766125L;
@JsonProperty("keys")
private List<String> keys;

View File

@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.HashMap;
@@ -34,6 +35,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class SecretMetadata implements Serializable {
@Serial
private static final long serialVersionUID = -905059942871916214L;
@JsonProperty("created_time")

View File

@@ -3,6 +3,7 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
@@ -15,6 +16,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecretWrapper implements Serializable {
@Serial
private static final long serialVersionUID = 8600413181758893378L;
@JsonProperty("data")

View File

@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.List;
@@ -34,6 +35,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenData implements Serializable {
@Serial
private static final long serialVersionUID = -4168046151053509784L;
@JsonProperty("accessor")

View File

@@ -3,6 +3,7 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
@@ -14,6 +15,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class UserLockoutConfig implements Serializable {
@Serial
private static final long serialVersionUID = -8051060041593140550L;
@JsonProperty("lockout_threshold")

View File

@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.HashMap;
@@ -34,6 +35,7 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class VersionMetadata implements Serializable {
@Serial
private static final long serialVersionUID = 8495687554714216478L;
@JsonProperty("created_time")

View File

@@ -18,6 +18,7 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.Objects;
@@ -29,6 +30,7 @@ import java.util.Objects;
* @since 1.1
*/
public class WrapInfo implements Serializable {
@Serial
private static final long serialVersionUID = 4864973237090355607L;
@JsonProperty("token")

View File

@@ -95,10 +95,10 @@ class HTTPVaultConnectorIT {
connector = builder.build();
// Unseal Vault and check result.
SealResponse sealStatus = connector.sys().unseal(KEY1);
SealResponse sealStatus = connector.unseal(KEY1);
assumeTrue(sealStatus != null, "Seal status could not be determined after startup");
assumeTrue(sealStatus.isSealed(), "Vault is not sealed after startup");
sealStatus = connector.sys().unseal(KEY2);
sealStatus = connector.unseal(KEY2);
assumeTrue(sealStatus != null, "Seal status could not be determined");
assumeFalse(sealStatus.isSealed(), "Vault is not unsealed");
assumeTrue(sealStatus.isInitialized(), "Vault is not initialized"); // Initialized flag of Vault 0.11.2 (#20).
@@ -337,7 +337,7 @@ class HTTPVaultConnectorIT {
// Try to read accessible path with known value.
SecretResponse res = assertDoesNotThrow(
() -> connector.kv2().readData(MOUNT_KV2, SECRET2_KEY),
() -> connector.readSecretData(MOUNT_KV2, SECRET2_KEY),
"Valid secret path could not be read"
);
assertNotNull(res.getMetadata(), "Metadata not populated for KV v2 secret");
@@ -346,7 +346,7 @@ class HTTPVaultConnectorIT {
// Try to read different version of same secret.
res = assertDoesNotThrow(
() -> connector.kv2().readVersion(MOUNT_KV2, SECRET2_KEY, 1),
() -> connector.readSecretVersion(MOUNT_KV2, SECRET2_KEY, 1),
"Valid secret version could not be read"
);
assertEquals(1, res.getMetadata().getVersion(), "Unexpected secret version");
@@ -365,7 +365,7 @@ class HTTPVaultConnectorIT {
// First get the current version of the secret.
MetadataResponse res = assertDoesNotThrow(
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading secret metadata failed"
);
int currentVersion = res.getMetadata().getCurrentVersion();
@@ -374,7 +374,7 @@ class HTTPVaultConnectorIT {
Map<String, Object> data = new HashMap<>();
data.put("value", SECRET2_VALUE3);
SecretVersionResponse res2 = assertDoesNotThrow(
() -> connector.kv2().writeData(MOUNT_KV2, SECRET2_KEY, data),
() -> connector.writeSecretData(MOUNT_KV2, SECRET2_KEY, data),
"Writing secret to KV v2 store failed"
);
assertEquals(currentVersion + 1, res2.getMetadata().getVersion(), "Version not updated after writing secret");
@@ -382,7 +382,7 @@ class HTTPVaultConnectorIT {
// Verify the content.
SecretResponse res3 = assertDoesNotThrow(
() -> connector.kv2().readData(MOUNT_KV2, SECRET2_KEY),
() -> connector.readSecretData(MOUNT_KV2, SECRET2_KEY),
"Reading secret from KV v2 store failed"
);
assertEquals(SECRET2_VALUE3, res3.get("value"), "Data not updated correctly");
@@ -391,13 +391,13 @@ class HTTPVaultConnectorIT {
Map<String, Object> data4 = singletonMap("value", SECRET2_VALUE4);
assertThrows(
InvalidResponseException.class,
() -> connector.kv2().writeData(MOUNT_KV2, SECRET2_KEY, data4, currentVersion2 - 1),
() -> connector.writeSecretData(MOUNT_KV2, SECRET2_KEY, data4, currentVersion2 - 1),
"Writing secret to KV v2 with invalid CAS value succeeded"
);
// And finally with a correct CAS value.
Map<String, Object> data5 = singletonMap("value", SECRET2_VALUE4);
assertDoesNotThrow(() -> connector.kv2().writeData(MOUNT_KV2, SECRET2_KEY, data5, currentVersion2));
assertDoesNotThrow(() -> connector.writeSecretData(MOUNT_KV2, SECRET2_KEY, data5, currentVersion2));
}
/**
@@ -412,7 +412,7 @@ class HTTPVaultConnectorIT {
// Read current metadata first.
MetadataResponse res = assertDoesNotThrow(
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading secret metadata failed"
);
Integer maxVersions = res.getMetadata().getMaxVersions();
@@ -420,13 +420,13 @@ class HTTPVaultConnectorIT {
// Now update the metadata.
assertDoesNotThrow(
() -> connector.kv2().updateMetadata(MOUNT_KV2, SECRET2_KEY, maxVersions + 1, true),
() -> connector.updateSecretMetadata(MOUNT_KV2, SECRET2_KEY, maxVersions + 1, true),
"Updating secret metadata failed"
);
// And verify the result.
res = assertDoesNotThrow(
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading secret metadata failed"
);
assertEquals(maxVersions + 1, res.getMetadata().getMaxVersions(), "Unexpected maximum number of versions");
@@ -444,7 +444,7 @@ class HTTPVaultConnectorIT {
// Try to read accessible path with known value.
MetadataResponse res = assertDoesNotThrow(
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
"Valid secret path could not be read"
);
assertNotNull(res.getMetadata(), "Metadata not populated for KV v2 secret");
@@ -467,21 +467,21 @@ class HTTPVaultConnectorIT {
// Try to delete non-existing versions.
assertDoesNotThrow(
() -> connector.kv2().deleteVersions(MOUNT_KV2, SECRET2_KEY, 5, 42),
() -> connector.deleteSecretVersions(MOUNT_KV2, SECRET2_KEY, 5, 42),
"Revealed non-existence of secret versions"
);
assertDoesNotThrow(
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
"Revealed non-existence of secret versions"
);
// Now delete existing version and verify.
assertDoesNotThrow(
() -> connector.kv2().deleteVersions(MOUNT_KV2, SECRET2_KEY, 1),
() -> connector.deleteSecretVersions(MOUNT_KV2, SECRET2_KEY, 1),
"Deleting existing version failed"
);
MetadataResponse meta = assertDoesNotThrow(
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading deleted secret metadata failed"
);
assertNotNull(
@@ -491,11 +491,11 @@ class HTTPVaultConnectorIT {
// Undelete the just deleted version.
assertDoesNotThrow(
() -> connector.kv2().undeleteVersions(MOUNT_KV2, SECRET2_KEY, 1),
() -> connector.undeleteSecretVersions(MOUNT_KV2, SECRET2_KEY, 1),
"Undeleting existing version failed"
);
meta = assertDoesNotThrow(
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading deleted secret metadata failed"
);
assertNull(
@@ -505,11 +505,11 @@ class HTTPVaultConnectorIT {
// Now destroy it.
assertDoesNotThrow(
() -> connector.kv2().destroyVersions(MOUNT_KV2, SECRET2_KEY, 1),
() -> connector.destroySecretVersions(MOUNT_KV2, SECRET2_KEY, 1),
"Destroying existing version failed"
);
meta = assertDoesNotThrow(
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading destroyed secret metadata failed"
);
assertTrue(
@@ -519,11 +519,11 @@ class HTTPVaultConnectorIT {
// Delete latest version.
assertDoesNotThrow(
() -> connector.kv2().deleteLatestVersion(MOUNT_KV2, SECRET2_KEY),
() -> connector.deleteLatestSecretVersion(MOUNT_KV2, SECRET2_KEY),
"Deleting latest version failed"
);
meta = assertDoesNotThrow(
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading deleted secret metadata failed"
);
assertNotNull(
@@ -533,12 +533,12 @@ class HTTPVaultConnectorIT {
// Delete all versions.
assertDoesNotThrow(
() -> connector.kv2().deleteAllVersions(MOUNT_KV2, SECRET2_KEY),
() -> connector.deleteAllSecretVersions(MOUNT_KV2, SECRET2_KEY),
"Deleting latest version failed"
);
assertThrows(
InvalidResponseException.class,
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading metadata of deleted secret should not succeed"
);
}
@@ -620,21 +620,21 @@ class HTTPVaultConnectorIT {
// Try unauthorized access first.
assumeFalse(connector.isAuthorized());
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().listRoles());
assertThrows(AuthorizationRequiredException.class, () -> connector.listAppRoles());
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().listSecrets(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.listAppRoleSecrets(""));
// Authorize.
authRoot();
assumeTrue(connector.isAuthorized());
// Verify pre-existing rules.
List<String> res = assertDoesNotThrow(() -> connector.appRole().listRoles(), "Role listing failed");
List<String> res = assertDoesNotThrow(() -> connector.listAppRoles(), "Role listing failed");
assertEquals(2, res.size(), "Unexpected number of AppRoles");
assertTrue(res.containsAll(List.of(APPROLE_ROLE_NAME, APPROLE_ROLE2_NAME)), "Pre-configured roles not listed");
// Check secret IDs.
res = assertDoesNotThrow(() -> connector.appRole().listSecrets(APPROLE_ROLE_NAME), "AppRole secret listing failed");
res = assertDoesNotThrow(() -> connector.listAppRoleSecrets(APPROLE_ROLE_NAME), "AppRole secret listing failed");
assertEquals(List.of(APPROLE_SECRET_ACCESSOR), res, "Pre-configured AppRole secret not listed");
}
@@ -647,14 +647,14 @@ class HTTPVaultConnectorIT {
void createAppRoleTest() {
// Try unauthorized access first.
assumeFalse(connector.isAuthorized());
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().create(new AppRole()));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().lookup(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().delete(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().getRoleID(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().setRoleID("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().createSecret("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().lookupSecret("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().destroySecret("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.createAppRole(new AppRole()));
assertThrows(AuthorizationRequiredException.class, () -> connector.lookupAppRole(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.deleteAppRole(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.getAppRoleID(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.setAppRoleID("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.createAppRoleSecret("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.lookupAppRoleSecret("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.destroyAppRoleSecret("", ""));
// Authorize.
authRoot();
@@ -666,23 +666,23 @@ class HTTPVaultConnectorIT {
AppRole role = AppRole.builder(roleName).build();
// Create role.
boolean createRes = assertDoesNotThrow(() -> connector.appRole().create(role), "Role creation failed");
boolean createRes = assertDoesNotThrow(() -> connector.createAppRole(role), "Role creation failed");
assertTrue(createRes, "Role creation failed");
// Lookup role.
AppRoleResponse res = assertDoesNotThrow(() -> connector.appRole().lookup(roleName), "Role lookup failed");
AppRoleResponse res = assertDoesNotThrow(() -> connector.lookupAppRole(roleName), "Role lookup failed");
assertNotNull(res.getRole(), "Role lookup returned no role");
// Lookup role ID.
String roleID = assertDoesNotThrow(() -> connector.appRole().getRoleID(roleName), "Role ID lookup failed");
String roleID = assertDoesNotThrow(() -> connector.getAppRoleID(roleName), "Role ID lookup failed");
assertNotEquals("", roleID, "Role ID lookup returned empty ID");
// Set custom role ID.
String roleID2 = "custom-role-id";
assertDoesNotThrow(() -> connector.appRole().setRoleID(roleName, roleID2), "Setting custom role ID failed");
assertDoesNotThrow(() -> connector.setAppRoleID(roleName, roleID2), "Setting custom role ID failed");
// Verify role ID.
String res2 = assertDoesNotThrow(() -> connector.appRole().getRoleID(roleName), "Role ID lookup failed");
String res2 = assertDoesNotThrow(() -> connector.getAppRoleID(roleName), "Role ID lookup failed");
assertEquals(roleID2, res2, "Role ID lookup returned wrong ID");
// Update role model with custom flags.
@@ -691,44 +691,44 @@ class HTTPVaultConnectorIT {
.build();
// Create role.
boolean res3 = assertDoesNotThrow(() -> connector.appRole().create(role2), "Role creation failed");
boolean res3 = assertDoesNotThrow(() -> connector.createAppRole(role2), "Role creation failed");
assertTrue(res3, "No result given");
// Lookup updated role.
res = assertDoesNotThrow(() -> connector.appRole().lookup(roleName), "Role lookup failed");
res = assertDoesNotThrow(() -> connector.lookupAppRole(roleName), "Role lookup failed");
assertNotNull(res.getRole(), "Role lookup returned no role");
assertEquals(321, res.getRole().getTokenPeriod(), "Token period not set for role");
// Create role by name.
String roleName2 = "RoleByName";
assertDoesNotThrow(() -> connector.appRole().create(roleName2), "Creation of role by name failed");
res = assertDoesNotThrow(() -> connector.appRole().lookup(roleName2), "Creation of role by name failed");
assertDoesNotThrow(() -> connector.createAppRole(roleName2), "Creation of role by name failed");
res = assertDoesNotThrow(() -> connector.lookupAppRole(roleName2), "Creation of role by name failed");
assertNotNull(res.getRole(), "Role lookuo returned not value");
// Create role by name with custom ID.
String roleName3 = "RoleByName";
String roleID3 = "RolyByNameID";
assertDoesNotThrow(() -> connector.appRole().create(roleName3, roleID3), "Creation of role by name failed");
res = assertDoesNotThrow(() -> connector.appRole().lookup(roleName3), "Creation of role by name failed");
assertDoesNotThrow(() -> connector.createAppRole(roleName3, roleID3), "Creation of role by name failed");
res = assertDoesNotThrow(() -> connector.lookupAppRole(roleName3), "Creation of role by name failed");
assertNotNull(res.getRole(), "Role lookuo returned not value");
res2 = assertDoesNotThrow(() -> connector.appRole().getRoleID(roleName3), "Creation of role by name failed");
res2 = assertDoesNotThrow(() -> connector.getAppRoleID(roleName3), "Creation of role by name failed");
assertEquals(roleID3, res2, "Role lookuo returned wrong ID");
// Create role by name with policies.
assertDoesNotThrow(
() -> connector.appRole().create(roleName3, Collections.singletonList("testpolicy")),
() -> connector.createAppRole(roleName3, Collections.singletonList("testpolicy")),
"Creation of role by name failed"
);
res = assertDoesNotThrow(() -> connector.appRole().lookup(roleName3), "Creation of role by name failed");
res = assertDoesNotThrow(() -> connector.lookupAppRole(roleName3), "Creation of role by name failed");
// Note: As of Vault 0.8.3 default policy is not added automatically, so this test should return 1, not 2.
assertEquals(List.of("testpolicy"), res.getRole().getTokenPolicies(), "Role lookup returned unexpected policies");
// Delete role.
assertDoesNotThrow(() -> connector.appRole().delete(roleName3), "Deletion of role failed");
assertDoesNotThrow(() -> connector.deleteAppRole(roleName3), "Deletion of role failed");
assertThrows(
InvalidResponseException.class,
() -> connector.appRole().lookup(roleName3),
() -> connector.lookupAppRole(roleName3),
"Deleted role could be looked up"
);
}
@@ -745,7 +745,7 @@ class HTTPVaultConnectorIT {
// Create default (random) secret for existing role.
AppRoleSecretResponse res = assertDoesNotThrow(
() -> connector.appRole().createSecret(APPROLE_ROLE_NAME),
() -> connector.createAppRoleSecret(APPROLE_ROLE_NAME),
"AppRole secret creation failed"
);
assertNotNull(res.getSecret(), "No secret returned");
@@ -753,26 +753,26 @@ class HTTPVaultConnectorIT {
// Create secret with custom ID.
String secretID = "customSecretId";
res = assertDoesNotThrow(
() -> connector.appRole().createSecret(APPROLE_ROLE_NAME, secretID),
() -> connector.createAppRoleSecret(APPROLE_ROLE_NAME, secretID),
"AppRole secret creation failed"
);
assertEquals(secretID, res.getSecret().getId(), "Unexpected secret ID returned");
// Lookup secret.
res = assertDoesNotThrow(
() -> connector.appRole().lookupSecret(APPROLE_ROLE_NAME, secretID),
() -> connector.lookupAppRoleSecret(APPROLE_ROLE_NAME, secretID),
"AppRole secret lookup failed"
);
assertNotNull(res.getSecret(), "No secret information returned");
// Destroy secret.
assertDoesNotThrow(
() -> connector.appRole().destroySecret(APPROLE_ROLE_NAME, secretID),
() -> connector.destroyAppRoleSecret(APPROLE_ROLE_NAME, secretID),
"AppRole secret destruction failed"
);
assertThrows(
InvalidResponseException.class,
() -> connector.appRole().lookupSecret(APPROLE_ROLE_NAME, secretID),
() -> connector.lookupAppRoleSecret(APPROLE_ROLE_NAME, secretID),
"Destroyed AppRole secret successfully read"
);
}
@@ -825,7 +825,7 @@ class HTTPVaultConnectorIT {
.build();
// Create token.
AuthResponse res = assertDoesNotThrow(() -> connector.token().create(token), "Token creation failed");
AuthResponse res = assertDoesNotThrow(() -> connector.createToken(token), "Token creation failed");
assertNotNull(res, "No result given");
assertEquals("test-id", res.getAuth().getClientToken(), "Invalid token ID returned");
assertEquals(List.of("root"), res.getAuth().getPolicies(), "Expected inherited root policy");
@@ -847,7 +847,7 @@ class HTTPVaultConnectorIT {
.withoutDefaultPolicy()
.withMeta("foo", "bar")
.build();
res = assertDoesNotThrow(() -> connector.token().create(token2), "Token creation failed");
res = assertDoesNotThrow(() -> connector.createToken(token2), "Token creation failed");
assertEquals("test-id2", res.getAuth().getClientToken(), "Invalid token ID returned");
assertEquals(List.of("testpolicy"), res.getAuth().getPolicies(), "Invalid policies returned");
assertNotNull(res.getAuth().getMetadata(), "Metadata not given");
@@ -866,7 +866,7 @@ class HTTPVaultConnectorIT {
.build();
InvalidResponseException e = assertThrows(
InvalidResponseException.class,
() -> connector.token().create(token3),
() -> connector.createToken(token3),
"Overwriting token should fail as of Vault 0.8.0"
);
assertEquals(400, e.getStatusCode());
@@ -880,7 +880,7 @@ class HTTPVaultConnectorIT {
.withoutDefaultPolicy()
.withType(Token.Type.BATCH)
.build();
res = assertDoesNotThrow(() -> connector.token().create(token4), "Token creation failed");
res = assertDoesNotThrow(() -> connector.createToken(token4), "Token creation failed");
assertTrue(
// Expecting batch token. "hvb." Prefix as of Vault 1.10, "b." before.
res.getAuth().getClientToken().startsWith("b.") || res.getAuth().getClientToken().startsWith("hvb."),
@@ -908,12 +908,12 @@ class HTTPVaultConnectorIT {
.withId("my-token")
.withType(Token.Type.SERVICE)
.build();
assertDoesNotThrow(() -> connector.token().create(token), "Token creation failed");
assertDoesNotThrow(() -> connector.createToken(token), "Token creation failed");
authRoot();
assumeTrue(connector.isAuthorized());
TokenResponse res = assertDoesNotThrow(() -> connector.token().lookup("my-token"), "Token creation failed");
TokenResponse res = assertDoesNotThrow(() -> connector.lookupToken("my-token"), "Token creation failed");
assertEquals(token.getId(), res.getData().getId(), "Unexpected token ID");
assertEquals(1, res.getData().getPolicies().size(), "Unexpected number of policies");
assertTrue(res.getData().getPolicies().contains("root"), "Unexpected policy");
@@ -936,14 +936,14 @@ class HTTPVaultConnectorIT {
final TokenRole role = TokenRole.builder().build();
boolean creationRes = assertDoesNotThrow(
() -> connector.token().createOrUpdateRole(roleName, role),
() -> connector.createOrUpdateTokenRole(roleName, role),
"Token role creation failed"
);
assertTrue(creationRes, "Token role creation failed");
// Read the role.
TokenRoleResponse res = assertDoesNotThrow(
() -> connector.token().readRole(roleName),
() -> connector.readTokenRole(roleName),
"Reading token role failed"
);
assertNotNull(res, "Token role response must not be null");
@@ -963,12 +963,12 @@ class HTTPVaultConnectorIT {
.build();
creationRes = assertDoesNotThrow(
() -> connector.token().createOrUpdateRole(role2),
() -> connector.createOrUpdateTokenRole(role2),
"Token role update failed"
);
assertTrue(creationRes, "Token role update failed");
res = assertDoesNotThrow(() -> connector.token().readRole(roleName), "Reading token role failed");
res = assertDoesNotThrow(() -> connector.readTokenRole(roleName), "Reading token role failed");
assertNotNull(res, "Token role response must not be null");
assertNotNull(res.getData(), "Token role must not be null");
assertEquals(roleName, res.getData().getName(), "Token role name not as expected");
@@ -977,15 +977,15 @@ class HTTPVaultConnectorIT {
assertEquals(42, res.getData().getTokenNumUses(), "Unexpected number of token uses after update");
// List roles.
List<String> listRes = assertDoesNotThrow(() -> connector.token().listRoles(), "Listing token roles failed");
List<String> listRes = assertDoesNotThrow(() -> connector.listTokenRoles(), "Listing token roles failed");
assertNotNull(listRes, "Token role list must not be null");
assertEquals(List.of(roleName), listRes, "Unexpected token role list");
// Delete the role.
creationRes = assertDoesNotThrow(() -> connector.token().deleteRole(roleName), "Token role deletion failed");
creationRes = assertDoesNotThrow(() -> connector.deleteTokenRole(roleName), "Token role deletion failed");
assertTrue(creationRes, "Token role deletion failed");
assertThrows(InvalidResponseException.class, () -> connector.token().readRole(roleName), "Reading nonexistent token role should fail");
assertThrows(InvalidResponseException.class, () -> connector.token().listRoles(), "Listing nonexistent token roles should fail");
assertThrows(InvalidResponseException.class, () -> connector.readTokenRole(roleName), "Reading nonexistent token role should fail");
assertThrows(InvalidResponseException.class, () -> connector.listTokenRoles(), "Listing nonexistent token roles should fail");
}
}
@@ -1000,14 +1000,14 @@ class HTTPVaultConnectorIT {
assumeTrue(connector.isAuthorized());
TransitResponse transitResponse = assertDoesNotThrow(
() -> connector.transit().encrypt("my-key", "dGVzdCBtZQ=="),
() -> connector.transitEncrypt("my-key", "dGVzdCBtZQ=="),
"Failed to encrypt via transit"
);
assertNotNull(transitResponse.getCiphertext());
assertTrue(transitResponse.getCiphertext().startsWith("vault:v1:"));
transitResponse = assertDoesNotThrow(
() -> connector.transit().encrypt("my-key", "test me".getBytes(UTF_8)),
() -> connector.transitEncrypt("my-key", "test me".getBytes(UTF_8)),
"Failed to encrypt binary data via transit"
);
assertNotNull(transitResponse.getCiphertext());
@@ -1022,7 +1022,7 @@ class HTTPVaultConnectorIT {
assumeTrue(connector.isAuthorized());
TransitResponse transitResponse = assertDoesNotThrow(
() -> connector.transit().decrypt("my-key", "vault:v1:1mhLVkBAR2nrFtIkJF/qg57DWfRj0FWgR6tvkGO8XOnL6sw="),
() -> connector.transitDecrypt("my-key", "vault:v1:1mhLVkBAR2nrFtIkJF/qg57DWfRj0FWgR6tvkGO8XOnL6sw="),
"Failed to decrypt via transit"
);
@@ -1036,21 +1036,21 @@ class HTTPVaultConnectorIT {
assumeTrue(connector.isAuthorized());
TransitResponse transitResponse = assertDoesNotThrow(
() -> connector.transit().hash("sha2-512", "dGVzdCBtZQ=="),
() -> connector.transitHash("sha2-512", "dGVzdCBtZQ=="),
"Failed to hash via transit"
);
assertEquals("7677af0ee4effaa9f35e9b1e82d182f79516ab8321786baa23002de7c06851059492dd37d5fc3791f17d81d4b58198d24a6fd8bbd62c42c1c30b371da500f193", transitResponse.getSum());
TransitResponse transitResponseBase64 = assertDoesNotThrow(
() -> connector.transit().hash("sha2-256", "dGVzdCBtZQ==", "base64"),
() -> connector.transitHash("sha2-256", "dGVzdCBtZQ==", "base64"),
"Failed to hash via transit with base64 output"
);
assertEquals("5DfYkW7cvGLkfy36cXhqmZcygEy9HpnFNB4WWXKOl1M=", transitResponseBase64.getSum());
transitResponseBase64 = assertDoesNotThrow(
() -> connector.transit().hash("sha2-256", "test me".getBytes(UTF_8), "base64"),
() -> connector.transitHash("sha2-256", "test me".getBytes(UTF_8), "base64"),
"Failed to hash binary data via transit"
);
@@ -1072,7 +1072,7 @@ class HTTPVaultConnectorIT {
assumeTrue(connector.isAuthorized());
List<AuthBackend> supportedBackends = assertDoesNotThrow(
() -> connector.sys().getAuthBackends(),
() -> connector.getAuthBackends(),
"Could not list supported auth backends"
);
@@ -1132,22 +1132,22 @@ class HTTPVaultConnectorIT {
@Test
@DisplayName("Seal test")
void sealTest() throws VaultConnectorException {
SealResponse sealStatus = connector.sys().sealStatus();
SealResponse sealStatus = connector.sealStatus();
assumeFalse(sealStatus.isSealed());
// Unauthorized sealing should fail.
assertThrows(VaultConnectorException.class, () -> connector.sys().seal(), "Unauthorized sealing succeeded");
assertThrows(VaultConnectorException.class, connector::seal, "Unauthorized sealing succeeded");
assertFalse(sealStatus.isSealed(), "Vault sealed, although sealing failed");
// Root user should be able to seal.
authRoot();
assumeTrue(connector.isAuthorized());
assertDoesNotThrow(() -> connector.sys().seal(), "Sealing failed");
sealStatus = connector.sys().sealStatus();
assertDoesNotThrow(connector::seal, "Sealing failed");
sealStatus = connector.sealStatus();
assertTrue(sealStatus.isSealed(), "Vault not sealed");
sealStatus = connector.sys().unseal(KEY2);
sealStatus = connector.unseal(KEY2);
assertTrue(sealStatus.isSealed(), "Vault unsealed with only 1 key");
sealStatus = connector.sys().unseal(KEY3);
sealStatus = connector.unseal(KEY3);
assertFalse(sealStatus.isSealed(), "Vault not unsealed");
}
@@ -1157,7 +1157,7 @@ class HTTPVaultConnectorIT {
@Test
@DisplayName("Health test")
void healthTest() {
HealthResponse res = assertDoesNotThrow(() -> connector.sys().getHealth(), "Retrieving health status failed");
HealthResponse res = assertDoesNotThrow(connector::getHealth, "Retrieving health status failed");
assertNotNull(res, "Health response should be set");
assertEquals(VAULT_VERSION, res.getVersion(), "Unexpected version");
assertTrue(res.isInitialized(), "Unexpected init status");
@@ -1166,11 +1166,11 @@ class HTTPVaultConnectorIT {
// No seal vault and verify correct status.
authRoot();
assertDoesNotThrow(() -> connector.sys().seal(), "Unexpected exception on sealing");
SealResponse sealStatus = assertDoesNotThrow(() -> connector.sys().sealStatus());
assertDoesNotThrow(connector::seal, "Unexpected exception on sealing");
SealResponse sealStatus = assertDoesNotThrow(connector::sealStatus);
assumeTrue(sealStatus.isSealed());
connector.resetAuth(); // Should work unauthenticated
res = assertDoesNotThrow(() -> connector.sys().getHealth(), "Retrieving health status failed when sealed");
res = assertDoesNotThrow(connector::getHealth, "Retrieving health status failed when sealed");
assertTrue(res.isSealed(), "Unexpected seal status");
}

View File

@@ -54,51 +54,51 @@ class HTTPVaultConnectorTest {
*/
@Test
void requestExceptionTest(WireMockRuntimeInfo wireMock) throws IOException, URISyntaxException {
try (var connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build()) {
// Test invalid response code.
final int responseCode = 400;
mockHttpResponse(responseCode, "", "application/json");
VaultConnectorException e = assertThrows(
InvalidResponseException.class,
() -> connector.sys().getHealth(),
"Querying health status succeeded on invalid instance"
);
assertEquals("Invalid response code", e.getMessage(), "Unexpected exception message");
assertEquals(responseCode, ((InvalidResponseException) e).getStatusCode(), "Unexpected status code in exception");
assertNull(((InvalidResponseException) e).getResponse(), "Response message where none was expected");
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build();
// Simulate permission denied response.
mockHttpResponse(responseCode, "{\"errors\":[\"permission denied\"]}", "application/json");
assertThrows(
PermissionDeniedException.class,
() -> connector.sys().getHealth(),
"Querying health status succeeded on invalid instance"
);
}
// Test invalid response code.
final int responseCode = 400;
mockHttpResponse(responseCode, "", "application/json");
VaultConnectorException e = assertThrows(
InvalidResponseException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
assertEquals("Invalid response code", e.getMessage(), "Unexpected exception message");
assertEquals(responseCode, ((InvalidResponseException) e).getStatusCode(), "Unexpected status code in exception");
assertNull(((InvalidResponseException) e).getResponse(), "Response message where none was expected");
// Simulate permission denied response.
mockHttpResponse(responseCode, "{\"errors\":[\"permission denied\"]}", "application/json");
assertThrows(
PermissionDeniedException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
// Test exception thrown during request.
try (ServerSocket s = new ServerSocket(0);
var connector = HTTPVaultConnector.builder("http://localst:" + s.getLocalPort() + "/").withTimeout(250).build()) {
var e = assertThrows(
ConnectionException.class,
() -> connector.sys().getHealth(),
"Querying health status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
assertInstanceOf(IOException.class, e.getCause(), "Unexpected cause");
try (ServerSocket s = new ServerSocket(0)) {
connector = HTTPVaultConnector.builder("http://localst:" + s.getLocalPort() + "/").withTimeout(250).build();
}
e = assertThrows(
ConnectionException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
assertInstanceOf(IOException.class, e.getCause(), "Unexpected cause");
// Now simulate a failing request that succeeds on second try.
try (var connector3 = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withNumberOfRetries(1).withTimeout(250).build()) {
stubFor(
WireMock.any(anyUrl())
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(200).withBody("{}").withHeader("Content-Type", "application/json"))
);
assertDoesNotThrow(() -> connector3.sys().getHealth(), "Request failed unexpectedly");
}
connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withNumberOfRetries(1).withTimeout(250).build();
stubFor(
WireMock.any(anyUrl())
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(200).withBody("{}").withHeader("Content-Type", "application/json"))
);
assertDoesNotThrow(connector::getHealth, "Request failed unexpectedly");
}
/**
@@ -160,7 +160,7 @@ class HTTPVaultConnectorTest {
}
ConnectionException e = assertThrows(
ConnectionException.class,
() -> connector.sys().sealStatus(),
connector::sealStatus,
"Querying seal status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
@@ -178,7 +178,7 @@ class HTTPVaultConnectorTest {
}
ConnectionException e = assertThrows(
ConnectionException.class,
() -> connector.sys().getHealth(),
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
@@ -196,21 +196,21 @@ class HTTPVaultConnectorTest {
mockHttpResponse(200, "invalid", "application/json");
// Now test the methods.
assertParseError(() -> connector.sys().sealStatus(), "sys().sealStatus() succeeded on invalid instance");
assertParseError(() -> connector.sys().unseal("key"), "sys().unseal() succeeded on invalid instance");
assertParseError(() -> connector.sys().getHealth(), "sys().getHealth() succeeded on invalid instance");
assertParseError(() -> connector.sys().getAuthBackends(), "sys().getAuthBackends() succeeded on invalid instance");
assertParseError(connector::sealStatus, "sealStatus() succeeded on invalid instance");
assertParseError(() -> connector.unseal("key"), "unseal() succeeded on invalid instance");
assertParseError(connector::getHealth, "getHealth() succeeded on invalid instance");
assertParseError(connector::getAuthBackends, "getAuthBackends() succeeded on invalid instance");
assertParseError(() -> connector.authToken("token"), "authToken() succeeded on invalid instance");
assertParseError(() -> connector.appRole().lookup("roleName"), "appRole().lookup() succeeded on invalid instance");
assertParseError(() -> connector.appRole().getRoleID("roleName"), "appRole().getRoleID() succeeded on invalid instance");
assertParseError(() -> connector.appRole().createSecret("roleName"), "appRole().createSecret() succeeded on invalid instance");
assertParseError(() -> connector.appRole().lookupSecret("roleName", "secretID"), "appRole().lookupSecret() succeeded on invalid instance");
assertParseError(() -> connector.appRole().listRoles(), "appRole().listRoles() succeeded on invalid instance");
assertParseError(() -> connector.appRole().listSecrets("roleName"), "appRole().listSecrets() succeeded on invalid instance");
assertParseError(() -> connector.lookupAppRole("roleName"), "lookupAppRole() succeeded on invalid instance");
assertParseError(() -> connector.getAppRoleID("roleName"), "getAppRoleID() succeeded on invalid instance");
assertParseError(() -> connector.createAppRoleSecret("roleName"), "createAppRoleSecret() succeeded on invalid instance");
assertParseError(() -> connector.lookupAppRoleSecret("roleName", "secretID"), "lookupAppRoleSecret() succeeded on invalid instance");
assertParseError(connector::listAppRoles, "listAppRoles() succeeded on invalid instance");
assertParseError(() -> connector.listAppRoleSecrets("roleName"), "listAppRoleSecrets() succeeded on invalid instance");
assertParseError(() -> connector.read("key"), "read() succeeded on invalid instance");
assertParseError(() -> connector.list("path"), "list() succeeded on invalid instance");
assertParseError(() -> connector.renew("leaseID"), "renew() succeeded on invalid instance");
assertParseError(() -> connector.token().lookup("token"), "token().lookup() succeeded on invalid instance");
assertParseError(() -> connector.lookupToken("token"), "lookupToken() succeeded on invalid instance");
}
private void assertParseError(Executable executable, String message) {
@@ -232,32 +232,32 @@ class HTTPVaultConnectorTest {
// Now test the methods expecting a 204.
assertThrows(
InvalidResponseException.class,
() -> connector.appRole().create("appID", Collections.singletonList("policy")),
"appRole().create() with 200 response succeeded"
() -> connector.createAppRole("appID", Collections.singletonList("policy")),
"createAppRole() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.delete("roleName"),
"appRole().delete() with 200 response succeeded"
() -> connector.deleteAppRole("roleName"),
"deleteAppRole() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.appRole().setRoleID("roleName", "roleID"),
"appRole().setRoleID() with 200 response succeeded"
() -> connector.setAppRoleID("roleName", "roleID"),
"setAppRoleID() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.appRole().destroySecret("roleName", "secretID"),
"appRole().destroySecret() with 200 response succeeded"
() -> connector.destroyAppRoleSecret("roleName", "secretID"),
"destroyAppRoleSecret() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.appRole().destroySecret("roleName", "secretUD"),
"appRole().destroySecret() with 200 response succeeded"
() -> connector.destroyAppRoleSecret("roleName", "secretUD"),
"destroyAppRoleSecret() with 200 response succeeded"
);
assertThrows(