diff --git a/src/main/java/com/bettercloud/vault/api/Auth.java b/src/main/java/com/bettercloud/vault/api/Auth.java index 0e193c8e..a811b137 100644 --- a/src/main/java/com/bettercloud/vault/api/Auth.java +++ b/src/main/java/com/bettercloud/vault/api/Auth.java @@ -857,6 +857,71 @@ public AuthResponse loginByGithub(final String githubToken, final String githubA } } + /** + *

Basic login operation to authenticate to an JWT/OIDC backend. Example usage:

+ * + *
+ *
{@code
+     * final AuthResponse response = vault.auth().loginByJWT("role", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "jwt");
+     *
+     * final String token = response.getAuthClientToken();
+     * }
+ *
+ * + * @param role The jwt role used for authentication + * @param jwt Signed JSON Web Token (JWT) + * @param path Path the JWT auth backend is mounted + * @return The auth token, with additional response metadata + * @throws VaultException If any error occurs, or unexpected response received from Vault + */ + // TODO: Needs integration test coverage if possible + public AuthResponse loginByJWT(final String role, final String jwt, final String path) throws VaultException { + int retryCount = 0; + + while (true) { + try { + // HTTP request to Vault + final String requestJson = Json.object() + .add("role", role) + .add("jwt", jwt) + .toString(); + final RestResponse restResponse = new Rest() + .url(config.getAddress() + "/v1/auth/" + path + "/login") + .body(requestJson.getBytes("UTF-8")) + .connectTimeoutSeconds(config.getOpenTimeout()) + .readTimeoutSeconds(config.getReadTimeout()) + .sslVerification(config.getSslConfig().isVerify()) + .sslContext(config.getSslConfig().getSslContext()) + .post(); + + // Validate restResponse + if (restResponse.getStatus() != 200) { + throw new VaultException("Vault responded with HTTP status code: " + restResponse.getStatus(), restResponse.getStatus()); + } + final String mimeType = restResponse.getMimeType() == null ? "null" : restResponse.getMimeType(); + if (!mimeType.equals("application/json")) { + throw new VaultException("Vault responded with MIME type: " + mimeType, restResponse.getStatus()); + } + return new AuthResponse(restResponse, retryCount); + } catch (Exception e) { + // If there are retries to perform, then pause for the configured interval and then execute the loop again... + if (retryCount < config.getMaxRetries()) { + retryCount++; + try { + final int retryIntervalMilliseconds = config.getRetryIntervalMilliseconds(); + Thread.sleep(retryIntervalMilliseconds); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } else if (e instanceof VaultException) { + // ... otherwise, give up. + throw (VaultException) e; + } else { + throw new VaultException(e); + } + } + } + } /** *

Basic login operation to authenticate to an GCP backend. Example usage:

* diff --git a/src/test-integration/java/com/bettercloud/vault/util/VaultContainer.java b/src/test-integration/java/com/bettercloud/vault/util/VaultContainer.java index f86519c7..8f5a6c5f 100644 --- a/src/test-integration/java/com/bettercloud/vault/util/VaultContainer.java +++ b/src/test-integration/java/com/bettercloud/vault/util/VaultContainer.java @@ -34,7 +34,7 @@ public class VaultContainer implements TestRule, TestConstants { /** Establishes a running Docker container, hosting a Vault server instance. */ public VaultContainer() { - container = new GenericContainer("vault:0.9.1") + container = new GenericContainer("vault:0.10.4") .withClasspathResourceMapping("/startup.sh", CONTAINER_STARTUP_SCRIPT, BindMode.READ_ONLY) .withClasspathResourceMapping("/config.json", CONTAINER_CONFIG_FILE, BindMode.READ_ONLY) .withClasspathResourceMapping("/libressl.conf", CONTAINER_OPENSSL_CONFIG_FILE, BindMode.READ_ONLY)