From 269a8e128e541fc6d3b7c85ce7f1657a61f7036c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 1 Nov 2023 16:02:13 +0100 Subject: [PATCH] Polishing. Reorder methods. Reformat code. Add since tags. Convert revocation timestamp into instant. See: gh-477 Original pull request: gh-820 --- .../vault/core/VaultPkiOperations.java | 52 +++--- .../vault/core/VaultPkiTemplate.java | 10 +- .../vault/support/Certificate.java | 27 ++- .../support/VaultCertificateRequest.java | 117 +++++++------ ...VaultIssuerCertificateRequestResponse.java | 3 +- .../VaultPkiTemplateIntegrationTests.java | 159 ++++++++++-------- 6 files changed, 216 insertions(+), 152 deletions(-) diff --git a/spring-vault-core/src/main/java/org/springframework/vault/core/VaultPkiOperations.java b/spring-vault-core/src/main/java/org/springframework/vault/core/VaultPkiOperations.java index a7d99f2a..e66fd516 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/core/VaultPkiOperations.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/core/VaultPkiOperations.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2022 the original author or authors. + * Copyright 2016-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ import org.springframework.vault.support.VaultSignCertificateRequestResponse; * provide the verification functionality. * * @author Mark Paluch + * @author Nanne Baars * @see https://www.vaultproject.io/docs/secrets/pki/index.html */ @@ -66,10 +67,10 @@ public interface VaultPkiOperations { * @param certificateRequest must not be {@literal null}. * @return the {@link VaultCertificateResponse} containing a * {@link org.springframework.vault.support.Certificate} . - * @since 2.0 * @see POST * /pki/sign/[role name] + * @since 2.0 */ VaultSignCertificateRequestResponse signCertificateRequest(String roleName, String csr, VaultCertificateRequest certificateRequest) throws VaultException; @@ -79,10 +80,10 @@ public interface VaultPkiOperations { * standard method of revoking using Vault lease IDs. A successful revocation will * rotate the CRL * @param serialNumber must not be empty or {@literal null}. - * @since 2.0 * @see POST * /pki/revoke + * @since 2.0 */ void revoke(String serialNumber) throws VaultException; @@ -96,43 +97,56 @@ public interface VaultPkiOperations { * is {@literal null}. * @return {@link java.io.InputStream} containing the encoded CRL or {@literal null} * if Vault responds with 204 No Content. - * @since 2.0 * @see GET * /pki/crl + * @since 2.0 */ @Nullable InputStream getCrl(Encoding encoding) throws VaultException; - enum Encoding { - - DER, PEM, - - } - /** - * Retrieves the specified issuer's certificate. Includes the full ca_chain of the - * issuer. + * Retrieves the specified issuer's certificate. Includes the full {@code ca_chain} of + * the issuer. * @param issuer reference to an existing issuer, either by Vault-generated - * identifier, or the name assigned to an issuer. Pass the literal string 'default' to - * refer to the currently configured issuer. + * identifier, or the name assigned to an issuer. Pass the literal string + * {@code default} to refer to the currently configured issuer. * @return the {@link VaultIssuerCertificateRequestResponse} containing a * {@link org.springframework.vault.support.Certificate} * @see GET * * /pki/issuer/:issuer_ref/json - * + * @since 3.1 */ VaultIssuerCertificateRequestResponse getIssuerCertificate(String issuer) throws VaultException; /** - * Retrieves the specified issuer's certificate. Includes the full ca_chain of the - * issuer. - * @return {@link java.io.InputStream} containing the encoded certificate or - * {@literal null} + * Retrieves the specified issuer's certificate. Includes the full {@code ca_chain} of + * the issuer. + * @param issuer reference to an existing issuer, either by Vault-generated + * identifier, or the name assigned to an issuer. Pass the literal string + * {@code default} to refer to the currently configured issuer. + * @param encoding encoding to use. + * @return {@link java.io.InputStream} containing the encoded certificate. * @see GET * /pki/issuer/:issuer_ref/{der, pem} + * @since 3.1 */ InputStream getIssuerCertificate(String issuer, Encoding encoding) throws VaultException; + enum Encoding { + + /** + * DER (Distinguished Encoding Rules) format in its binary representation, see + * X.690. + */ + DER, + + /** + * Privacy-Enhanced Mail (PEM) format in base64. + */ + PEM; + + } + } diff --git a/spring-vault-core/src/main/java/org/springframework/vault/core/VaultPkiTemplate.java b/spring-vault-core/src/main/java/org/springframework/vault/core/VaultPkiTemplate.java index 2c2fde2f..7ddfb2ed 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/core/VaultPkiTemplate.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/core/VaultPkiTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2022 the original author or authors. + * Copyright 2016-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,11 @@ package org.springframework.vault.core; import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; @@ -165,12 +167,14 @@ public class VaultPkiTemplate implements VaultPkiOperations { @Override public InputStream getIssuerCertificate(String issuer, Encoding encoding) throws VaultException { + Assert.hasText(issuer, "Issuer must not be empty"); Assert.notNull(encoding, "Encoding must not be null"); return this.vaultOperations.doWithSession(restOperations -> { - String requestPath = encoding == Encoding.DER ? "{path}/issuer/{issuer}/der" : "{path}/issuer/{issuer}/pem"; + String requestPath = String.format("{path}/issuer/{issuer}/%s", encoding.name().toLowerCase(Locale.ROOT)); + try { ResponseEntity response = restOperations.getForEntity(requestPath, byte[].class, this.path, issuer); @@ -224,7 +228,7 @@ public class VaultPkiTemplate implements VaultPkiOperations { .to("exclude_cn_from_sans", request); mapper.from(certificateRequest::getFormat).whenHasText().to("format", request); mapper.from(certificateRequest::getPrivateKeyFormat).whenHasText().to("private_key_format", request); - mapper.from(certificateRequest::getNotAfter).whenHasText().as(i -> i.toString()).to("not_after", request); + mapper.from(certificateRequest::getNotAfter).whenHasText().as(Instant::toString).to("not_after", request); mapper.from(certificateRequest::getUserIds).whenHasText().to("user_ids", request); return request; diff --git a/spring-vault-core/src/main/java/org/springframework/vault/support/Certificate.java b/spring-vault-core/src/main/java/org/springframework/vault/support/Certificate.java index 8f27276e..7ed8e9e8 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/support/Certificate.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/support/Certificate.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2022 the original author or authors. + * Copyright 2017-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -36,9 +37,9 @@ import org.springframework.vault.VaultException; * encoded. Certificates can be obtained as {@link X509Certificate}. * * @author Mark Paluch - * @since 2.0 * @see #getX509Certificate() * @see #getIssuingCaCertificate() + * @since 2.0 */ public class Certificate { @@ -50,17 +51,18 @@ public class Certificate { private final List caChain; - private final Long revocationTime; + @Nullable + private final Instant revocationTime; Certificate(@JsonProperty("serial_number") String serialNumber, @JsonProperty("certificate") String certificate, @JsonProperty("issuing_ca") String issuingCaCertificate, @JsonProperty("ca_chain") List caChain, - @JsonProperty("revocation_time") Long revocationTime) { + @Nullable @JsonProperty("revocation_time") Long revocationTime) { this.serialNumber = serialNumber; this.certificate = certificate; this.issuingCaCertificate = issuingCaCertificate; this.caChain = caChain; - this.revocationTime = revocationTime; + this.revocationTime = revocationTime != null ? Instant.ofEpochMilli(revocationTime * 1000) : null; } /** @@ -87,7 +89,8 @@ public class Certificate { * @param certificate must not be empty or {@literal null}. * @param issuingCaCertificate must not be empty or {@literal null}. * @param caChain empty list allowed - * @return the {@link Certificate} + * @return the {@link Certificate}. + * @since 3.1 */ public static Certificate of(String serialNumber, String certificate, String issuingCaCertificate, List caChain) { @@ -107,8 +110,9 @@ public class Certificate { * @param certificate must not be empty or {@literal null}. * @param issuingCaCertificate must not be empty or {@literal null}. * @param caChain empty list allowed - * @param revocationTime revocation time, must not be {@literal null} - * @return the {@link Certificate} + * @param revocationTime revocation time, must not be {@literal null}. + * @return the {@link Certificate}. + * @since 3.1 */ public static Certificate of(String serialNumber, String certificate, String issuingCaCertificate, List caChain, Long revocationTime) { @@ -250,8 +254,13 @@ public class Certificate { return certificates; } - public @Nullable Long getRevocationTime() { + @Nullable + public Instant getRevocationTime() { return this.revocationTime; } + public boolean isRevoked() { + return this.revocationTime != null; + } + } diff --git a/spring-vault-core/src/main/java/org/springframework/vault/support/VaultCertificateRequest.java b/spring-vault-core/src/main/java/org/springframework/vault/support/VaultCertificateRequest.java index bd533215..91e4a4b8 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/support/VaultCertificateRequest.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/support/VaultCertificateRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2022 the original author or authors. + * Copyright 2016-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,14 @@ import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Locale; import java.util.concurrent.TimeUnit; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * Request for a Certificate. @@ -40,6 +43,13 @@ public class VaultCertificateRequest { */ private final String commonName; + /** + * If {@literal true}, the given common name will not be included in DNS or Email + * Subject Alternate Names (as appropriate). Useful if the CN is not a hostname or + * email address, but is instead some human-readable identifier. + */ + private final boolean excludeCommonNameFromSubjectAltNames; + /** * Alternate CN names for additional host names. */ @@ -59,6 +69,7 @@ public class VaultCertificateRequest { * Specifies custom OID/UTF8-string Subject Alternative Names. These must match values * specified on the role in {@literal allowed_other_sans}. The format is the same as * OpenSSL: {@literal ;:} where the only current valid type is UTF8. + * * @since 2.4 */ private final List otherSans; @@ -69,6 +80,14 @@ public class VaultCertificateRequest { @Nullable private final Duration ttl; + /** + * Set the Not After field of the certificate with specified date value. The value + * format should be given in UTC format YYYY-MM-ddTHH:MM:SSZ. Supports the Y10K end + * date for IEEE 802.1AR-2018 standard devices, 9999-12-31T23:59:59Z. + */ + @Nullable + private final Instant notAfter; + /** * Specifies the format for returned data. Can be {@literal pem}, {@literal der}, or * {@literal pem_bundle}; defaults to {@literal der} (in vault api the default is @@ -76,6 +95,7 @@ public class VaultCertificateRequest { * the certificate field will contain the private key and certificate, concatenated; * if the issuing CA is not a Vault-derived self-signed root, this will be included as * well. + * * @since 2.4 */ private final String format; @@ -85,49 +105,35 @@ public class VaultCertificateRequest { * which will return either base64-encoded DER or PEM-encoded DER, depending on the * value of {@literal format}. The other option is {@literal pkcs8} which will return * the key marshalled as PEM-encoded PKCS8. + * * @since 2.4 */ @Nullable private final String privateKeyFormat; - /** - * Set the Not After field of the certificate with specified date value. The value - * format should be given in UTC format YYYY-MM-ddTHH:MM:SSZ. Supports the Y10K end - * date for IEEE 802.1AR-2018 standard devices, 9999-12-31T23:59:59Z. - */ - @Nullable - private Instant notAfter; - /** * Specifies the comma-separated list of requested User ID (OID * 0.9.2342.19200300.100.1.1) Subject values to be placed on the signed certificate. * This field is validated against allowed_user_ids on the role. */ @Nullable - private String userIds; + private final String userIds; - /** - * If {@literal true}, the given common name will not be included in DNS or Email - * Subject Alternate Names (as appropriate). Useful if the CN is not a hostname or - * email address, but is instead some human-readable identifier. - */ - private final boolean excludeCommonNameFromSubjectAltNames; - - private VaultCertificateRequest(String commonName, List altNames, List ipSubjectAltNames, - List uriSubjectAltNames, List otherSans, @Nullable Duration ttl, String format, - @Nullable String privateKeyFormat, boolean excludeCommonNameFromSubjectAltNames, @Nullable Instant notAfter, - @Nullable String userIds) { + private VaultCertificateRequest(String commonName, boolean excludeCommonNameFromSubjectAltNames, + List altNames, List ipSubjectAltNames, List uriSubjectAltNames, + List otherSans, @Nullable Duration ttl, @Nullable Instant notAfter, String format, + @Nullable String privateKeyFormat, @Nullable String userIds) { this.commonName = commonName; + this.excludeCommonNameFromSubjectAltNames = excludeCommonNameFromSubjectAltNames; this.altNames = altNames; this.ipSubjectAltNames = ipSubjectAltNames; this.uriSubjectAltNames = uriSubjectAltNames; this.otherSans = otherSans; this.ttl = ttl; - this.excludeCommonNameFromSubjectAltNames = excludeCommonNameFromSubjectAltNames; + this.notAfter = notAfter; this.format = format; this.privateKeyFormat = privateKeyFormat; - this.notAfter = notAfter; this.userIds = userIds; } @@ -240,6 +246,18 @@ public class VaultCertificateRequest { return this; } + /** + * Exclude the given common name from DNS or Email Subject Alternate Names (as + * appropriate). Useful if the CN is not a hostname or email address, but is + * instead some human-readable identifier. + * @return {@code this} {@link VaultCertificateRequestBuilder}. + */ + public VaultCertificateRequestBuilder excludeCommonNameFromSubjectAltNames() { + + this.excludeCommonNameFromSubjectAltNames = true; + return this; + } + /** * Configure alternative names. Replaces previously configured alt names. * @param altNames must not be {@literal null}. @@ -381,6 +399,21 @@ public class VaultCertificateRequest { return this; } + /** + * Set the {@code Not After} field of the certificate with specified date value. + * Supports the Y10K end date for IEEE 802.1AR-2018 standard devices, + * 9999-12-31T23:59:59Z. + * @return {@code this} {@link VaultCertificateRequestBuilder}. + * @since 3.1 + */ + public VaultCertificateRequestBuilder notAfter(Instant notAfter) { + + Assert.notNull(notAfter, "Not after must not be null"); + + this.notAfter = Instant.from(notAfter).truncatedTo(ChronoUnit.SECONDS); + return this; + } + /** * Configure the certificate format. * @param format the certificate format to use. Can be {@code pem}, {@code der}, @@ -412,28 +445,17 @@ public class VaultCertificateRequest { } /** - * Exclude the given common name from DNS or Email Subject Alternate Names (as - * appropriate). Useful if the CN is not a hostname or email address, but is - * instead some human-readable identifier. + * Specifies the comma-separated list of requested User ID (OID + * 0.9.2342.19200300.100.1.1) Subject values to be placed on the signed + * certificate. This field is validated against allowed_user_ids on the role. * @return {@code this} {@link VaultCertificateRequestBuilder}. + * @since 3.1 */ - public VaultCertificateRequestBuilder excludeCommonNameFromSubjectAltNames() { + public VaultCertificateRequestBuilder userId(String userId) { - this.excludeCommonNameFromSubjectAltNames = true; - return this; - } + Assert.hasText(userId, "User ID must not be empty or null"); - /** - * Set the Not After field of the certificate with specified date value. The value - * format should be given in UTC format YYYY-MM-ddTHH:MM:SSZ. Supports the Y10K - * end date for IEEE 802.1AR-2018 standard devices, 9999-12-31T23:59:59Z. - * @return {@code this} {@link VaultCertificateRequestBuilder}. - */ - public VaultCertificateRequestBuilder notAfter(Instant notAfter) { - - Assert.notNull(notAfter, "Not after must not be null"); - - this.notAfter = Instant.from(notAfter).truncatedTo(ChronoUnit.SECONDS); + this.userIds = userId; return this; } @@ -442,12 +464,13 @@ public class VaultCertificateRequest { * 0.9.2342.19200300.100.1.1) Subject values to be placed on the signed * certificate. This field is validated against allowed_user_ids on the role. * @return {@code this} {@link VaultCertificateRequestBuilder}. + * @since 3.1 */ - public VaultCertificateRequestBuilder userIds(String userIds) { + public VaultCertificateRequestBuilder userIds(Collection userIds) { - Assert.hasText(userIds, "User IDs must not be empty or null"); + Assert.notNull(userIds, "User IDs must not be null"); - this.userIds = userIds; + this.userIds = StringUtils.collectionToCommaDelimitedString(userIds); return this; } @@ -510,9 +533,9 @@ public class VaultCertificateRequest { otherSans = java.util.Collections.unmodifiableList(new ArrayList<>(this.otherSans)); } - return new VaultCertificateRequest(this.commonName, altNames, ipSubjectAltNames, uriSubjectAltNames, - otherSans, this.ttl, this.format, this.privateKeyFormat, this.excludeCommonNameFromSubjectAltNames, - notAfter, userIds); + return new VaultCertificateRequest(this.commonName, this.excludeCommonNameFromSubjectAltNames, altNames, + ipSubjectAltNames, uriSubjectAltNames, otherSans, this.ttl, notAfter, this.format, + this.privateKeyFormat, userIds); } private static List toList(Iterable iter) { diff --git a/spring-vault-core/src/main/java/org/springframework/vault/support/VaultIssuerCertificateRequestResponse.java b/spring-vault-core/src/main/java/org/springframework/vault/support/VaultIssuerCertificateRequestResponse.java index 05782636..c3b2cb4a 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/support/VaultIssuerCertificateRequestResponse.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/support/VaultIssuerCertificateRequestResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2022 the original author or authors. + * Copyright 2017-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.vault.support; * Value object to bind Vault HTTP PKI issue certificate API responses. * * @author Nanne Baars + * @since 3.1 */ public class VaultIssuerCertificateRequestResponse extends VaultResponseSupport { diff --git a/spring-vault-core/src/test/java/org/springframework/vault/core/VaultPkiTemplateIntegrationTests.java b/spring-vault-core/src/test/java/org/springframework/vault/core/VaultPkiTemplateIntegrationTests.java index f26f5055..c14c7aa0 100644 --- a/spring-vault-core/src/test/java/org/springframework/vault/core/VaultPkiTemplateIntegrationTests.java +++ b/spring-vault-core/src/test/java/org/springframework/vault/core/VaultPkiTemplateIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2022 the original author or authors. + * Copyright 2016-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,8 +59,10 @@ import org.springframework.vault.util.RequiresVaultVersion; import org.springframework.vault.util.Version; import org.springframework.web.client.HttpClientErrorException; -import static org.assertj.core.api.Assertions.*; -import static org.springframework.vault.util.Settings.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.springframework.vault.util.Settings.findWorkDir; /** * Integration tests for {@link VaultPkiTemplate} through {@link VaultPkiOperations}. @@ -268,24 +270,27 @@ class VaultPkiTemplateIntegrationTests extends IntegrationTestSupport { @Test void signShouldSignCsrWithNotAfter() { + Instant notAfter = Instant.now().plus(50, ChronoUnit.DAYS); - String csr = "-----BEGIN CERTIFICATE REQUEST-----\n" - + "MIICzTCCAbUCAQAwgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRl\n" - + "MRUwEwYDVQQHEwxTYW4gVmF1bHRpbm8xFTATBgNVBAoTDFNwcmluZyBWYXVsdDEY\n" - + "MBYGA1UEAxMPY3NyLmV4YW1wbGUuY29tMRswGQYJKoZIhvcNAQkBFgxzcHJpbmdA\n" - + "dmF1bHQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVlDBT1gAONIp4\n" - + "GQQ7BWDeqNzlscWqu5oQyfvw6oNFZzYWGVTgX/n72biv8d1Wx30MWpVYhbL0mk9m\n" - + "Uu15elMZHPb4F4bk8VDSiB9527SwAd/QpkNC1RsPp2h6g2LvGPJ2eidHSlLtF2To\n" - + "A4i6z0K0++nvYKSf9Af0sod2Z51xc9uPj/oN5z/8BQuGoCBpxJqgl7N/csMICixY\n" - + "2fQcCUbdPPqE9INIInUHe3mPE/yvxko9aYGZ5jnrdZyiQaRRKBdWpvbRLKXQ78Fz\n" - + "vXR3G33yn9JAN6wl1A916DiXzy2xHT19vyAn1hBUj2M6KFXChQ30oxTyTOqHCMLP\n" - + "m/BSEOsPAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAYFssueiUh3YGxnXcQ4dp\n" - + "ZqVWeVyOuGGaFJ4BA0drwJ9Mt/iNmPUTGE2oBNnh2R7e7HwGcNysFHZZOZBEQ0Hh\n" - + "Vn93GO7cfaTOetK0VtDqis1VFQD0eVPWf5s6UqT/+XGrFRhwJ9hM+2FQSrUDFecs\n" - + "+/605n1rD7qOj3vkGrtwvEUrxyRaQaKpPLHmVHENqV6F1NsO3Z27f2FWWAZF2VKN\n" - + "cCQQJNc//DbIN3J3JSElpIDBDHctoBoQVnMiwpCbSA+CaAtlWYJKnAfhTKeqnNMy\n" - + "qf3ACZ+1sBIuqSP7dEJ2KfIezaCPQ88+PAloRB52LFa+iq3yI7F5VzkwAvQFnTi+\n" + "cQ==\n" - + "-----END CERTIFICATE REQUEST-----"; + String csr = """ + -----BEGIN CERTIFICATE REQUEST----- + MIICzTCCAbUCAQAwgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRl + MRUwEwYDVQQHEwxTYW4gVmF1bHRpbm8xFTATBgNVBAoTDFNwcmluZyBWYXVsdDEY + MBYGA1UEAxMPY3NyLmV4YW1wbGUuY29tMRswGQYJKoZIhvcNAQkBFgxzcHJpbmdA + dmF1bHQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVlDBT1gAONIp4 + GQQ7BWDeqNzlscWqu5oQyfvw6oNFZzYWGVTgX/n72biv8d1Wx30MWpVYhbL0mk9m + Uu15elMZHPb4F4bk8VDSiB9527SwAd/QpkNC1RsPp2h6g2LvGPJ2eidHSlLtF2To + A4i6z0K0++nvYKSf9Af0sod2Z51xc9uPj/oN5z/8BQuGoCBpxJqgl7N/csMICixY + 2fQcCUbdPPqE9INIInUHe3mPE/yvxko9aYGZ5jnrdZyiQaRRKBdWpvbRLKXQ78Fz + vXR3G33yn9JAN6wl1A916DiXzy2xHT19vyAn1hBUj2M6KFXChQ30oxTyTOqHCMLP + m/BSEOsPAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAYFssueiUh3YGxnXcQ4dp + ZqVWeVyOuGGaFJ4BA0drwJ9Mt/iNmPUTGE2oBNnh2R7e7HwGcNysFHZZOZBEQ0Hh + Vn93GO7cfaTOetK0VtDqis1VFQD0eVPWf5s6UqT/+XGrFRhwJ9hM+2FQSrUDFecs + +/605n1rD7qOj3vkGrtwvEUrxyRaQaKpPLHmVHENqV6F1NsO3Z27f2FWWAZF2VKN + cCQQJNc//DbIN3J3JSElpIDBDHctoBoQVnMiwpCbSA+CaAtlWYJKnAfhTKeqnNMy + qf3ACZ+1sBIuqSP7dEJ2KfIezaCPQ88+PAloRB52LFa+iq3yI7F5VzkwAvQFnTi+ + cQ== + -----END CERTIFICATE REQUEST-----"""; VaultCertificateRequest request = VaultCertificateRequest.builder() .commonName("hello.example.com") @@ -302,27 +307,30 @@ class VaultPkiTemplateIntegrationTests extends IntegrationTestSupport { @Test @RequiresVaultVersion("1.14.2") void signShouldFailWithUnknownUserIds() { - String csr = "-----BEGIN CERTIFICATE REQUEST-----\n" - + "MIICzTCCAbUCAQAwgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRl\n" - + "MRUwEwYDVQQHEwxTYW4gVmF1bHRpbm8xFTATBgNVBAoTDFNwcmluZyBWYXVsdDEY\n" - + "MBYGA1UEAxMPY3NyLmV4YW1wbGUuY29tMRswGQYJKoZIhvcNAQkBFgxzcHJpbmdA\n" - + "dmF1bHQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVlDBT1gAONIp4\n" - + "GQQ7BWDeqNzlscWqu5oQyfvw6oNFZzYWGVTgX/n72biv8d1Wx30MWpVYhbL0mk9m\n" - + "Uu15elMZHPb4F4bk8VDSiB9527SwAd/QpkNC1RsPp2h6g2LvGPJ2eidHSlLtF2To\n" - + "A4i6z0K0++nvYKSf9Af0sod2Z51xc9uPj/oN5z/8BQuGoCBpxJqgl7N/csMICixY\n" - + "2fQcCUbdPPqE9INIInUHe3mPE/yvxko9aYGZ5jnrdZyiQaRRKBdWpvbRLKXQ78Fz\n" - + "vXR3G33yn9JAN6wl1A916DiXzy2xHT19vyAn1hBUj2M6KFXChQ30oxTyTOqHCMLP\n" - + "m/BSEOsPAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAYFssueiUh3YGxnXcQ4dp\n" - + "ZqVWeVyOuGGaFJ4BA0drwJ9Mt/iNmPUTGE2oBNnh2R7e7HwGcNysFHZZOZBEQ0Hh\n" - + "Vn93GO7cfaTOetK0VtDqis1VFQD0eVPWf5s6UqT/+XGrFRhwJ9hM+2FQSrUDFecs\n" - + "+/605n1rD7qOj3vkGrtwvEUrxyRaQaKpPLHmVHENqV6F1NsO3Z27f2FWWAZF2VKN\n" - + "cCQQJNc//DbIN3J3JSElpIDBDHctoBoQVnMiwpCbSA+CaAtlWYJKnAfhTKeqnNMy\n" - + "qf3ACZ+1sBIuqSP7dEJ2KfIezaCPQ88+PAloRB52LFa+iq3yI7F5VzkwAvQFnTi+\n" + "cQ==\n" - + "-----END CERTIFICATE REQUEST-----"; + + String csr = """ + -----BEGIN CERTIFICATE REQUEST----- + MIICzTCCAbUCAQAwgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRl + MRUwEwYDVQQHEwxTYW4gVmF1bHRpbm8xFTATBgNVBAoTDFNwcmluZyBWYXVsdDEY + MBYGA1UEAxMPY3NyLmV4YW1wbGUuY29tMRswGQYJKoZIhvcNAQkBFgxzcHJpbmdA + dmF1bHQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVlDBT1gAONIp4 + GQQ7BWDeqNzlscWqu5oQyfvw6oNFZzYWGVTgX/n72biv8d1Wx30MWpVYhbL0mk9m + Uu15elMZHPb4F4bk8VDSiB9527SwAd/QpkNC1RsPp2h6g2LvGPJ2eidHSlLtF2To + A4i6z0K0++nvYKSf9Af0sod2Z51xc9uPj/oN5z/8BQuGoCBpxJqgl7N/csMICixY + 2fQcCUbdPPqE9INIInUHe3mPE/yvxko9aYGZ5jnrdZyiQaRRKBdWpvbRLKXQ78Fz + vXR3G33yn9JAN6wl1A916DiXzy2xHT19vyAn1hBUj2M6KFXChQ30oxTyTOqHCMLP + m/BSEOsPAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAYFssueiUh3YGxnXcQ4dp + ZqVWeVyOuGGaFJ4BA0drwJ9Mt/iNmPUTGE2oBNnh2R7e7HwGcNysFHZZOZBEQ0Hh + Vn93GO7cfaTOetK0VtDqis1VFQD0eVPWf5s6UqT/+XGrFRhwJ9hM+2FQSrUDFecs + +/605n1rD7qOj3vkGrtwvEUrxyRaQaKpPLHmVHENqV6F1NsO3Z27f2FWWAZF2VKN + cCQQJNc//DbIN3J3JSElpIDBDHctoBoQVnMiwpCbSA+CaAtlWYJKnAfhTKeqnNMy + qf3ACZ+1sBIuqSP7dEJ2KfIezaCPQ88+PAloRB52LFa+iq3yI7F5VzkwAvQFnTi+ + cQ== + -----END CERTIFICATE REQUEST-----"""; VaultCertificateRequest request = VaultCertificateRequest.builder() .commonName("hello.example.com") - .userIds("test1,test2") + .userIds(List.of("test1", "test2")) .build(); assertThatThrownBy(() -> this.pkiOperations.signCertificateRequest("testrole", csr, request)) @@ -333,27 +341,29 @@ class VaultPkiTemplateIntegrationTests extends IntegrationTestSupport { @Test @RequiresVaultVersion("1.14.2") void signShouldSignWithKnownUserIds() { - String csr = "-----BEGIN CERTIFICATE REQUEST-----\n" - + "MIICzTCCAbUCAQAwgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRl\n" - + "MRUwEwYDVQQHEwxTYW4gVmF1bHRpbm8xFTATBgNVBAoTDFNwcmluZyBWYXVsdDEY\n" - + "MBYGA1UEAxMPY3NyLmV4YW1wbGUuY29tMRswGQYJKoZIhvcNAQkBFgxzcHJpbmdA\n" - + "dmF1bHQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVlDBT1gAONIp4\n" - + "GQQ7BWDeqNzlscWqu5oQyfvw6oNFZzYWGVTgX/n72biv8d1Wx30MWpVYhbL0mk9m\n" - + "Uu15elMZHPb4F4bk8VDSiB9527SwAd/QpkNC1RsPp2h6g2LvGPJ2eidHSlLtF2To\n" - + "A4i6z0K0++nvYKSf9Af0sod2Z51xc9uPj/oN5z/8BQuGoCBpxJqgl7N/csMICixY\n" - + "2fQcCUbdPPqE9INIInUHe3mPE/yvxko9aYGZ5jnrdZyiQaRRKBdWpvbRLKXQ78Fz\n" - + "vXR3G33yn9JAN6wl1A916DiXzy2xHT19vyAn1hBUj2M6KFXChQ30oxTyTOqHCMLP\n" - + "m/BSEOsPAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAYFssueiUh3YGxnXcQ4dp\n" - + "ZqVWeVyOuGGaFJ4BA0drwJ9Mt/iNmPUTGE2oBNnh2R7e7HwGcNysFHZZOZBEQ0Hh\n" - + "Vn93GO7cfaTOetK0VtDqis1VFQD0eVPWf5s6UqT/+XGrFRhwJ9hM+2FQSrUDFecs\n" - + "+/605n1rD7qOj3vkGrtwvEUrxyRaQaKpPLHmVHENqV6F1NsO3Z27f2FWWAZF2VKN\n" - + "cCQQJNc//DbIN3J3JSElpIDBDHctoBoQVnMiwpCbSA+CaAtlWYJKnAfhTKeqnNMy\n" - + "qf3ACZ+1sBIuqSP7dEJ2KfIezaCPQ88+PAloRB52LFa+iq3yI7F5VzkwAvQFnTi+\n" + "cQ==\n" - + "-----END CERTIFICATE REQUEST-----"; + String csr = """ + -----BEGIN CERTIFICATE REQUEST----- + MIICzTCCAbUCAQAwgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRl + MRUwEwYDVQQHEwxTYW4gVmF1bHRpbm8xFTATBgNVBAoTDFNwcmluZyBWYXVsdDEY + MBYGA1UEAxMPY3NyLmV4YW1wbGUuY29tMRswGQYJKoZIhvcNAQkBFgxzcHJpbmdA + dmF1bHQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVlDBT1gAONIp4 + GQQ7BWDeqNzlscWqu5oQyfvw6oNFZzYWGVTgX/n72biv8d1Wx30MWpVYhbL0mk9m + Uu15elMZHPb4F4bk8VDSiB9527SwAd/QpkNC1RsPp2h6g2LvGPJ2eidHSlLtF2To + A4i6z0K0++nvYKSf9Af0sod2Z51xc9uPj/oN5z/8BQuGoCBpxJqgl7N/csMICixY + 2fQcCUbdPPqE9INIInUHe3mPE/yvxko9aYGZ5jnrdZyiQaRRKBdWpvbRLKXQ78Fz + vXR3G33yn9JAN6wl1A916DiXzy2xHT19vyAn1hBUj2M6KFXChQ30oxTyTOqHCMLP + m/BSEOsPAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAYFssueiUh3YGxnXcQ4dp + ZqVWeVyOuGGaFJ4BA0drwJ9Mt/iNmPUTGE2oBNnh2R7e7HwGcNysFHZZOZBEQ0Hh + Vn93GO7cfaTOetK0VtDqis1VFQD0eVPWf5s6UqT/+XGrFRhwJ9hM+2FQSrUDFecs + +/605n1rD7qOj3vkGrtwvEUrxyRaQaKpPLHmVHENqV6F1NsO3Z27f2FWWAZF2VKN + cCQQJNc//DbIN3J3JSElpIDBDHctoBoQVnMiwpCbSA+CaAtlWYJKnAfhTKeqnNMy + qf3ACZ+1sBIuqSP7dEJ2KfIezaCPQ88+PAloRB52LFa+iq3yI7F5VzkwAvQFnTi+ + cQ== + -----END CERTIFICATE REQUEST-----"""; VaultCertificateRequest request = VaultCertificateRequest.builder() .commonName("hello.example.com") - .userIds("robot,humanoid") + .userIds(Arrays.asList("robot", "humanoid")) .build(); VaultSignCertificateRequestResponse certificateResponse = this.pkiOperations.signCertificateRequest("testrole", @@ -369,23 +379,25 @@ class VaultPkiTemplateIntegrationTests extends IntegrationTestSupport { @Test void signShouldSignCsr() { - String csr = "-----BEGIN CERTIFICATE REQUEST-----\n" - + "MIICzTCCAbUCAQAwgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRl\n" - + "MRUwEwYDVQQHEwxTYW4gVmF1bHRpbm8xFTATBgNVBAoTDFNwcmluZyBWYXVsdDEY\n" - + "MBYGA1UEAxMPY3NyLmV4YW1wbGUuY29tMRswGQYJKoZIhvcNAQkBFgxzcHJpbmdA\n" - + "dmF1bHQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVlDBT1gAONIp4\n" - + "GQQ7BWDeqNzlscWqu5oQyfvw6oNFZzYWGVTgX/n72biv8d1Wx30MWpVYhbL0mk9m\n" - + "Uu15elMZHPb4F4bk8VDSiB9527SwAd/QpkNC1RsPp2h6g2LvGPJ2eidHSlLtF2To\n" - + "A4i6z0K0++nvYKSf9Af0sod2Z51xc9uPj/oN5z/8BQuGoCBpxJqgl7N/csMICixY\n" - + "2fQcCUbdPPqE9INIInUHe3mPE/yvxko9aYGZ5jnrdZyiQaRRKBdWpvbRLKXQ78Fz\n" - + "vXR3G33yn9JAN6wl1A916DiXzy2xHT19vyAn1hBUj2M6KFXChQ30oxTyTOqHCMLP\n" - + "m/BSEOsPAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAYFssueiUh3YGxnXcQ4dp\n" - + "ZqVWeVyOuGGaFJ4BA0drwJ9Mt/iNmPUTGE2oBNnh2R7e7HwGcNysFHZZOZBEQ0Hh\n" - + "Vn93GO7cfaTOetK0VtDqis1VFQD0eVPWf5s6UqT/+XGrFRhwJ9hM+2FQSrUDFecs\n" - + "+/605n1rD7qOj3vkGrtwvEUrxyRaQaKpPLHmVHENqV6F1NsO3Z27f2FWWAZF2VKN\n" - + "cCQQJNc//DbIN3J3JSElpIDBDHctoBoQVnMiwpCbSA+CaAtlWYJKnAfhTKeqnNMy\n" - + "qf3ACZ+1sBIuqSP7dEJ2KfIezaCPQ88+PAloRB52LFa+iq3yI7F5VzkwAvQFnTi+\n" + "cQ==\n" - + "-----END CERTIFICATE REQUEST-----"; + String csr = """ + -----BEGIN CERTIFICATE REQUEST----- + MIICzTCCAbUCAQAwgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRl + MRUwEwYDVQQHEwxTYW4gVmF1bHRpbm8xFTATBgNVBAoTDFNwcmluZyBWYXVsdDEY + MBYGA1UEAxMPY3NyLmV4YW1wbGUuY29tMRswGQYJKoZIhvcNAQkBFgxzcHJpbmdA + dmF1bHQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVlDBT1gAONIp4 + GQQ7BWDeqNzlscWqu5oQyfvw6oNFZzYWGVTgX/n72biv8d1Wx30MWpVYhbL0mk9m + Uu15elMZHPb4F4bk8VDSiB9527SwAd/QpkNC1RsPp2h6g2LvGPJ2eidHSlLtF2To + A4i6z0K0++nvYKSf9Af0sod2Z51xc9uPj/oN5z/8BQuGoCBpxJqgl7N/csMICixY + 2fQcCUbdPPqE9INIInUHe3mPE/yvxko9aYGZ5jnrdZyiQaRRKBdWpvbRLKXQ78Fz + vXR3G33yn9JAN6wl1A916DiXzy2xHT19vyAn1hBUj2M6KFXChQ30oxTyTOqHCMLP + m/BSEOsPAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAYFssueiUh3YGxnXcQ4dp + ZqVWeVyOuGGaFJ4BA0drwJ9Mt/iNmPUTGE2oBNnh2R7e7HwGcNysFHZZOZBEQ0Hh + Vn93GO7cfaTOetK0VtDqis1VFQD0eVPWf5s6UqT/+XGrFRhwJ9hM+2FQSrUDFecs + +/605n1rD7qOj3vkGrtwvEUrxyRaQaKpPLHmVHENqV6F1NsO3Z27f2FWWAZF2VKN + cCQQJNc//DbIN3J3JSElpIDBDHctoBoQVnMiwpCbSA+CaAtlWYJKnAfhTKeqnNMy + qf3ACZ+1sBIuqSP7dEJ2KfIezaCPQ88+PAloRB52LFa+iq3yI7F5VzkwAvQFnTi+ + cQ== + -----END CERTIFICATE REQUEST-----"""; VaultCertificateRequest request = VaultCertificateRequest.create("hello.example.com"); @@ -450,6 +462,7 @@ class VaultPkiTemplateIntegrationTests extends IntegrationTestSupport { @Test void shouldReturnCA() throws Exception { + VaultIssuerCertificateRequestResponse certificateResponse = this.pkiOperations.getIssuerCertificate("default"); Certificate data = certificateResponse.getRequiredData();