From 55748531998918ab8750fe5f019e507c592c7d1b Mon Sep 17 00:00:00 2001 From: alzimmermsft <48699787+alzimmermsft@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:13:51 -0500 Subject: [PATCH 1/7] Update source to remove a few dependencies --- .../azure-security-keyvault-jca/pom.xml | 25 --- .../keyvault/jca/KeyVaultJcaProvider.java | 37 ++-- .../KeyVaultTrustManagerFactoryProvider.java | 1 + .../jca/implementation/KeyVaultClient.java | 40 ++-- .../certificates/ClasspathCertificates.java | 7 +- .../SpecificPathCertificates.java | 14 +- .../KeyVaultKeylessEcSha256Signature.java | 6 +- .../KeyVaultKeylessEcSha384Signature.java | 6 +- .../KeyVaultKeylessEcSha512Signature.java | 6 +- .../KeyVaultKeylessRsa256Signature.java | 14 +- .../KeyVaultKeylessRsa512Signature.java | 14 +- .../KeyVaultKeylessRsaSignature.java | 1 - .../KeyVaultKeylessRsaSsaPssSignature.java | 14 +- .../implementation/utils/AccessTokenUtil.java | 70 +++--- .../implementation/utils/CertificateUtil.java | 7 +- .../jca/implementation/utils/HttpUtil.java | 203 +++++++++--------- .../utils/JsonConverterUtil.java | 28 +-- .../keyvault/jca/PropertyConvertorUtils.java | 13 +- .../JreKeyStoreFactoryTest.java | 4 +- .../jca/implementation/JreKeyStoreTest.java | 7 +- .../KeyVaultCertificatesTest.java | 4 +- .../SpecificPathCertificatesTest.java | 4 +- .../KeyVaultKeylessEcSignatureTest.java | 5 +- .../implementation/utils/HttpUtilTest.java | 4 +- .../utils/JsonConverterUtilTest.java | 2 +- 25 files changed, 240 insertions(+), 296 deletions(-) diff --git a/sdk/keyvault/azure-security-keyvault-jca/pom.xml b/sdk/keyvault/azure-security-keyvault-jca/pom.xml index bd54cea363c3..d480be761abe 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/pom.xml +++ b/sdk/keyvault/azure-security-keyvault-jca/pom.xml @@ -35,18 +35,6 @@ 2.73.8 true - - - org.apache.httpcomponents.client5 - httpclient5 - 5.4.3 - - - org.brotli - dec - 0.1.2 - true - org.conscrypt @@ -88,19 +76,6 @@ 1.17.7 test - - - com.github.spotbugs - spotbugs-annotations - 4.8.3 - test - - - com.azure - azure-core - 1.57.1 - test - org.junit.jupiter diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultJcaProvider.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultJcaProvider.java index 99e70d955eab..bfd15e14c149 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultJcaProvider.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultJcaProvider.java @@ -3,20 +3,17 @@ package com.azure.security.keyvault.jca; -import com.azure.security.keyvault.jca.implementation.signature.KeyVaultKeylessRsa256Signature; -import com.azure.security.keyvault.jca.implementation.signature.KeyVaultKeylessRsa512Signature; +import com.azure.security.keyvault.jca.implementation.signature.KeyVaultKeylessEcSha256Signature; import com.azure.security.keyvault.jca.implementation.signature.KeyVaultKeylessEcSha384Signature; import com.azure.security.keyvault.jca.implementation.signature.KeyVaultKeylessEcSha512Signature; -import com.azure.security.keyvault.jca.implementation.signature.KeyVaultKeylessEcSha256Signature; -import com.azure.security.keyvault.jca.implementation.signature.AbstractKeyVaultKeylessSignature; +import com.azure.security.keyvault.jca.implementation.signature.KeyVaultKeylessRsa256Signature; +import com.azure.security.keyvault.jca.implementation.signature.KeyVaultKeylessRsa512Signature; import com.azure.security.keyvault.jca.implementation.signature.KeyVaultKeylessRsaSsaPssSignature; -import java.lang.reflect.InvocationTargetException; import java.security.PrivilegedAction; import java.security.Provider; import java.util.Arrays; import java.util.Collections; -import java.util.stream.Stream; /** * The Azure Key Vault security provider. @@ -48,6 +45,7 @@ public final class KeyVaultJcaProvider extends Provider { /** * Constructor. */ + @SuppressWarnings("deprecation") public KeyVaultJcaProvider() { super(PROVIDER_NAME, VERSION, INFO); initialize(); @@ -74,21 +72,20 @@ private void initialize() { Collections.singletonList("DKS"), null)); putService(new Provider.Service(this, "KeyStore", KeyVaultKeyStore.ALGORITHM_NAME, KeyVaultKeyStore.class.getName(), Collections.singletonList(KeyVaultKeyStore.ALGORITHM_NAME), null)); - Stream - .of(KeyVaultKeylessRsaSsaPssSignature.class, KeyVaultKeylessRsa256Signature.class, - KeyVaultKeylessRsa512Signature.class, KeyVaultKeylessEcSha256Signature.class, - KeyVaultKeylessEcSha384Signature.class, KeyVaultKeylessEcSha512Signature.class) - .forEach(c -> putService(new Service(this, "Signature", getAlgorithmName(c), c.getName(), null, null))); + + putService(new Service(this, "Signature", KeyVaultKeylessRsaSsaPssSignature.ALGORITHM_NAME, + KeyVaultKeylessRsaSsaPssSignature.class.getName(), null, null)); + putService(new Service(this, "Signature", KeyVaultKeylessRsa256Signature.ALGORITHM_NAME, + KeyVaultKeylessRsa256Signature.class.getName(), null, null)); + putService(new Service(this, "Signature", KeyVaultKeylessRsa512Signature.ALGORITHM_NAME, + KeyVaultKeylessRsa512Signature.class.getName(), null, null)); + putService(new Service(this, "Signature", KeyVaultKeylessEcSha256Signature.ALGORITHM_NAME, + KeyVaultKeylessEcSha256Signature.class.getName(), null, null)); + putService(new Service(this, "Signature", KeyVaultKeylessEcSha384Signature.ALGORITHM_NAME, + KeyVaultKeylessEcSha384Signature.class.getName(), null, null)); + putService(new Service(this, "Signature", KeyVaultKeylessEcSha512Signature.ALGORITHM_NAME, + KeyVaultKeylessEcSha512Signature.class.getName(), null, null)); return null; }); } - - private String getAlgorithmName(Class c) { - try { - return c.getDeclaredConstructor().newInstance().getAlgorithmName(); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException - | NoSuchMethodException e) { - return ""; - } - } } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManagerFactoryProvider.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManagerFactoryProvider.java index dafba85e114d..d911f502af88 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManagerFactoryProvider.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManagerFactoryProvider.java @@ -36,6 +36,7 @@ public final class KeyVaultTrustManagerFactoryProvider extends Provider { /** * Constructor. */ + @SuppressWarnings("deprecation") public KeyVaultTrustManagerFactoryProvider() { super(NAME, VERSION, INFO); initialize(); diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java index 045c69c52b68..725e3c999698 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java @@ -37,7 +37,7 @@ import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; import java.util.Base64; -import java.util.HashMap; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -258,11 +258,8 @@ private AccessToken obtainAccessToken() { public List getAliases() { LOGGER.entering("KeyVaultClient", "getAliases"); - ArrayList result = new ArrayList<>(); - HashMap headers = new HashMap<>(); - - headers.put("Authorization", "Bearer " + getAccessToken()); - + List result = new ArrayList<>(); + Map headers = Collections.singletonMap("Authorization", "Bearer " + getAccessToken()); String uri = keyVaultUri + "certificates" + API_VERSION_POSTFIX; while (uri != null && !uri.isEmpty()) { @@ -304,12 +301,8 @@ private CertificateBundle getCertificateBundle(String alias) { LOGGER.entering("KeyVaultClient", "getCertificateBundle", alias); CertificateBundle result = null; - HashMap headers = new HashMap<>(); - - headers.put("Authorization", "Bearer " + getAccessToken()); - - String uri = keyVaultUri + "certificates/" + alias + API_VERSION_POSTFIX; - String response = HttpUtil.get(uri, headers); + String response = HttpUtil.get(keyVaultUri + "certificates/" + alias + API_VERSION_POSTFIX, + Collections.singletonMap("Authorization", "Bearer " + getAccessToken())); if (response != null) { try { @@ -368,12 +361,8 @@ public Certificate[] getCertificateChain(String alias) { LOGGER.entering("KeyVaultClient", "getCertificateChain", alias); LOGGER.log(INFO, "Getting certificate chain for alias: {0}", alias); - HashMap headers = new HashMap<>(); - - headers.put("Authorization", "Bearer " + getAccessToken()); - String uri = keyVaultUri + "secrets/" + alias + API_VERSION_POSTFIX; - String response = HttpUtil.get(uri, headers); + String response = HttpUtil.get(uri, Collections.singletonMap("Authorization", "Bearer " + getAccessToken())); if (response == null) { throw new NullPointerException(); @@ -429,7 +418,8 @@ public Key getKey(String alias, char[] password) { // Return KeyVaultPrivateKey if certificate is not exportable because if the service needs to obtain the // private key for authentication, and we can't access private key(which is not exportable), we will use // the Azure Key Vault Secrets API to obtain the private key (keyless). - String keyType2 = keyType.contains("-HSM") ? keyType.substring(0, keyType.indexOf("-HSM")) : keyType; + int index = keyType.indexOf("-HSM"); + String keyType2 = (index == -1) ? keyType : keyType.substring(0, index); KeyVaultPrivateKey key = Optional.ofNullable(certificateBundle) .map(CertificateBundle::getKid) @@ -441,12 +431,8 @@ public Key getKey(String alias, char[] password) { return key; } - String certificateSecretUri = certificateBundle.getSid(); - Map headers = new HashMap<>(); - - headers.put("Authorization", "Bearer " + getAccessToken()); - - String body = HttpUtil.get(certificateSecretUri + API_VERSION_POSTFIX, headers); + String body = HttpUtil.get(certificateBundle.getSid() + API_VERSION_POSTFIX, + Collections.singletonMap("Authorization", "Bearer " + getAccessToken())); if (body == null) { // If the private key is not available the certificate cannot be used for server side certificates or mTLS. @@ -515,10 +501,8 @@ public byte[] getSignedWithPrivateKey(String digestName, String digestValue, Str LOGGER.entering("KeyVaultClient", "getSignedWithPrivateKey", new Object[] { digestName, digestValue, keyId }); SignResult result = null; - String bodyString = String.format("{\"alg\": \"" + digestName + "\", \"value\": \"%s\"}", digestValue); - Map headers = new HashMap<>(); - - headers.put("Authorization", "Bearer " + getAccessToken()); + String bodyString = "{\"alg\": \"" + digestName + "\", \"value\": \"" + digestValue + "\"}"; + Map headers = Collections.singletonMap("Authorization", "Bearer " + getAccessToken()); String uri = keyId + "/sign" + API_VERSION_POSTFIX; String response = HttpUtil.post(uri, headers, bodyString, "application/json"); diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/ClasspathCertificates.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/ClasspathCertificates.java index 1714a3c0334f..b1758198be00 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/ClasspathCertificates.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/ClasspathCertificates.java @@ -119,7 +119,7 @@ public void deleteEntry(String alias) { */ public void loadCertificatesFromClasspath() { try { - String[] filenames = getFilenames("/keyvault"); + String[] filenames = getFilenames(); for (String filename : filenames) { try (InputStream inputStream = getClass().getResourceAsStream("/keyvault/" + filename)) { String alias = filename; @@ -147,13 +147,12 @@ public void loadCertificatesFromClasspath() { /** * Get the filenames. * - * @param path the path. * @return the filenames. * @throws IOException when an I/O error occurs. */ - private String[] getFilenames(String path) throws IOException { + private String[] getFilenames() throws IOException { List filenames = new ArrayList<>(); - try (InputStream in = getClass().getResourceAsStream(path)) { + try (InputStream in = getClass().getResourceAsStream("/keyvault")) { if (!Objects.isNull(in)) { try (BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { String resource; diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/SpecificPathCertificates.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/SpecificPathCertificates.java index 30d66f230760..a68cbacf7e2f 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/SpecificPathCertificates.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/SpecificPathCertificates.java @@ -19,9 +19,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.logging.Logger; -import java.util.stream.Stream; import static com.azure.security.keyvault.jca.implementation.utils.CertificateUtil.loadX509CertificateFromFile; import static com.azure.security.keyvault.jca.implementation.utils.CertificateUtil.loadX509CertificatesFromFile; @@ -203,13 +201,11 @@ private List getFiles() { List files = new ArrayList<>(); File filePackage = new File(certificatePath); File[] array = filePackage.listFiles(); - Optional.ofNullable(array) - .map(Arrays::stream) - .orElseGet(Stream::empty) - .filter(Objects::nonNull) - .filter(File::isFile) - .filter(File::exists) - .filter(File::canRead) + if (array == null) { + return files; + } + Arrays.stream(array) + .filter(file -> Objects.nonNull(file) && file.exists() && file.isFile() && file.canRead()) .forEach(files::add); return files; } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha256Signature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha256Signature.java index a936e2722bdd..be8bf32deea7 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha256Signature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha256Signature.java @@ -6,10 +6,14 @@ * key vault SHA256 */ public final class KeyVaultKeylessEcSha256Signature extends KeyVaultKeylessEcSignature { + /** + * Algorithm name used by this implementation. + */ + public static String ALGORITHM_NAME = "SHA256withECDSA"; @Override public String getAlgorithmName() { - return "SHA256withECDSA"; + return ALGORITHM_NAME; } /** diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha384Signature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha384Signature.java index 0d267dfcd973..9e54533b6dac 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha384Signature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha384Signature.java @@ -6,10 +6,14 @@ * key vault SHA384 */ public final class KeyVaultKeylessEcSha384Signature extends KeyVaultKeylessEcSignature { + /** + * Algorithm name used by this implementation. + */ + public static String ALGORITHM_NAME = "SHA384withECDSA"; @Override public String getAlgorithmName() { - return "SHA384withECDSA"; + return ALGORITHM_NAME; } /** diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha512Signature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha512Signature.java index 23b9ff7b443e..a468501c1e18 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha512Signature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha512Signature.java @@ -6,10 +6,14 @@ * key vault SHA512 */ public final class KeyVaultKeylessEcSha512Signature extends KeyVaultKeylessEcSignature { + /** + * Algorithm name used by this implementation. + */ + public static String ALGORITHM_NAME = "SHA512withECDSA"; @Override public String getAlgorithmName() { - return "SHA512withECDSA"; + return ALGORITHM_NAME; } /** diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa256Signature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa256Signature.java index 3454bdb4716f..d73051353419 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa256Signature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa256Signature.java @@ -7,6 +7,15 @@ * key vault Rsa signature to support key less */ public class KeyVaultKeylessRsa256Signature extends KeyVaultKeylessRsaSignature { + /** + * Algorithm name used by this implementation. + */ + public static String ALGORITHM_NAME = "SHA256withRSA"; + + @Override + public String getAlgorithmName() { + return ALGORITHM_NAME; + } /** * Construct a new KeyVaultKeyLessRsaSignature @@ -14,9 +23,4 @@ public class KeyVaultKeylessRsa256Signature extends KeyVaultKeylessRsaSignature public KeyVaultKeylessRsa256Signature() { super("SHA-256", "RS256"); } - - @Override - public String getAlgorithmName() { - return "SHA256withRSA"; - } } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa512Signature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa512Signature.java index 3115057ecbef..4d153405190a 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa512Signature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa512Signature.java @@ -7,6 +7,15 @@ * key vault Rsa signature to support key less */ public class KeyVaultKeylessRsa512Signature extends KeyVaultKeylessRsaSignature { + /** + * Algorithm name used by this implementation. + */ + public static String ALGORITHM_NAME = "SHA512withRSA"; + + @Override + public String getAlgorithmName() { + return ALGORITHM_NAME; + } /** * Construct a new KeyVaultKeyLessRsaSignature @@ -14,9 +23,4 @@ public class KeyVaultKeylessRsa512Signature extends KeyVaultKeylessRsaSignature public KeyVaultKeylessRsa512Signature() { super("SHA-512", "RS512"); } - - @Override - public String getAlgorithmName() { - return "SHA512withRSA"; - } } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSignature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSignature.java index cc737a0750f0..83e56830a4ee 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSignature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSignature.java @@ -12,7 +12,6 @@ * key vault Rsa signature to support key less */ abstract class KeyVaultKeylessRsaSignature extends AbstractKeyVaultKeylessSignature { - private final String keyVaultDigestName; /** diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignature.java index d15df8aec525..0cd86b6bce05 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignature.java @@ -13,6 +13,15 @@ * key vault Rsa signature to support key less */ public class KeyVaultKeylessRsaSsaPssSignature extends KeyVaultKeylessRsaSignature { + /** + * Algorithm name used by this implementation. + */ + public static String ALGORITHM_NAME = "RSASSA-PSS"; + + @Override + public String getAlgorithmName() { + return ALGORITHM_NAME; + } /** * Construct a new KeyVaultKeyLessRsaSignature @@ -42,9 +51,4 @@ protected void engineSetParameter(AlgorithmParameterSpec params) throws InvalidA } } } - - @Override - public String getAlgorithmName() { - return "RSASSA-PSS"; - } } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/AccessTokenUtil.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/AccessTokenUtil.java index e7895c39958b..84ed43ff55aa 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/AccessTokenUtil.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/AccessTokenUtil.java @@ -3,7 +3,6 @@ package com.azure.security.keyvault.jca.implementation.utils; import com.azure.security.keyvault.jca.implementation.model.AccessToken; -import org.apache.hc.core5.http.ClassicHttpResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -12,6 +11,7 @@ import java.net.URLEncoder; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Logger; @@ -91,8 +91,10 @@ public static AccessToken getAccessToken(String resource, String identity) { /* * App Service 2017-09-01: MSI_ENDPOINT, MSI_SECRET - * Azure Container App 2019-08-01: IDENTITY_ENDPOINT, IDENTITY_HEADER, see more from https://learn.microsoft.com/en-us/azure/container-apps/managed-identity?tabs=cli%2Chttp#rest-endpoint-reference - * Azure Virtual Machine 2018-02-01, see more from https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http + * Azure Container App 2019-08-01: IDENTITY_ENDPOINT, IDENTITY_HEADER, see more from + * https://learn.microsoft.com/azure/container-apps/managed-identity?tabs=cli%2Chttp#rest-endpoint-reference + * Azure Virtual Machine 2018-02-01, see more from + * https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http */ if (System.getenv("WEBSITE_SITE_NAME") != null && !System.getenv("WEBSITE_SITE_NAME").isEmpty()) { result = getAccessTokenOnAppService(resource, identity); @@ -125,15 +127,9 @@ public static AccessToken getAccessToken(String resource, String aadAuthenticati AccessToken result = null; - StringBuilder oauth2Url = new StringBuilder(); - - if (aadAuthenticationUrl == null) { - oauth2Url.append(OAUTH2_TOKEN_BASE_URL).append(tenantId).append("/"); - } else { - oauth2Url.append(addTrailingSlashIfRequired(aadAuthenticationUrl)); - } - - oauth2Url.append(OAUTH2_TOKEN_POSTFIX); + String oauth2Url = (aadAuthenticationUrl == null) + ? OAUTH2_TOKEN_BASE_URL + tenantId + "/" + OAUTH2_TOKEN_POSTFIX + : addTrailingSlashIfRequired(aadAuthenticationUrl) + OAUTH2_TOKEN_POSTFIX; String encodedClientSecret = ""; @@ -143,17 +139,10 @@ public static AccessToken getAccessToken(String resource, String aadAuthenticati LOGGER.log(WARNING, "Failed to encode client secret for access token request", e); } - StringBuilder requestBody = new StringBuilder(); - - requestBody.append(GRANT_TYPE_FRAGMENT) - .append(CLIENT_ID_FRAGMENT) - .append(clientId) - .append(CLIENT_SECRET_FRAGMENT) - .append(encodedClientSecret) - .append(RESOURCE_FRAGMENT) - .append(resource); + String requestBody = GRANT_TYPE_FRAGMENT + CLIENT_ID_FRAGMENT + clientId + CLIENT_SECRET_FRAGMENT + + encodedClientSecret + RESOURCE_FRAGMENT + resource; - String body = HttpUtil.post(oauth2Url.toString(), requestBody.toString(), "application/x-www-form-urlencoded"); + String body = HttpUtil.post(oauth2Url, null, requestBody, "application/x-www-form-urlencoded"); if (body != null) { try { @@ -180,17 +169,13 @@ private static AccessToken getAccessTokenOnAppService(String resource, String cl LOGGER.info("Getting access token using managed identity based on MSI_SECRET"); AccessToken result = null; - StringBuilder url = new StringBuilder(); - - url.append(System.getenv("MSI_ENDPOINT")) - .append("?api-version=2017-09-01") - .append(RESOURCE_FRAGMENT) - .append(resource); - + String url; if (clientId != null) { - url.append("&clientid=").append(clientId); - + url = System.getenv("MSI_ENDPOINT") + "?api-version=2017-09-01" + RESOURCE_FRAGMENT + resource + + "&clientid=" + clientId; LOGGER.log(INFO, "Using managed identity with client ID: {0}", clientId); + } else { + url = System.getenv("MSI_ENDPOINT") + "?api-version=2017-09-01" + RESOURCE_FRAGMENT + resource; } HashMap headers = new HashMap<>(); @@ -198,7 +183,7 @@ private static AccessToken getAccessTokenOnAppService(String resource, String cl headers.put("Metadata", "true"); headers.put("Secret", System.getenv("MSI_SECRET")); - String body = HttpUtil.get(url.toString(), headers); + String body = HttpUtil.get(url, headers); if (body != null) { try { @@ -237,9 +222,9 @@ private static AccessToken getAccessTokenOnContainerApp(String resource, String LOGGER.log(INFO, "Using managed identity with client ID: {0}", clientId); } - Map headers = new HashMap<>(); + Map headers = Collections.emptyMap(); if (System.getenv(PROPERTY_IDENTITY_HEADER) != null && !System.getenv(PROPERTY_IDENTITY_HEADER).isEmpty()) { - headers.put("X-IDENTITY-HEADER", System.getenv(PROPERTY_IDENTITY_HEADER)); + headers = Collections.singletonMap("X-IDENTITY-HEADER", System.getenv(PROPERTY_IDENTITY_HEADER)); } String body = HttpUtil.get(url.toString(), headers); @@ -282,11 +267,7 @@ private static AccessToken getAccessTokenOnOthers(String resource, String identi url.append("&object_id=").append(identity); } - HashMap headers = new HashMap<>(); - - headers.put("Metadata", "true"); - - String body = HttpUtil.get(url.toString(), headers); + String body = HttpUtil.get(url.toString(), Collections.singletonMap("Metadata", "true")); if (body != null) { try { @@ -305,14 +286,15 @@ public static String getLoginUri(String resourceUri, boolean disableChallengeRes LOGGER.entering("AccessTokenUtil", "getLoginUri", resourceUri); LOGGER.log(INFO, "Getting login URI using: {0}", resourceUri); - ClassicHttpResponse response = HttpUtil.getWithResponse(resourceUri, null); + Map> headers = HttpUtil.getWithResponseHeadersOnlyReturn(resourceUri); - if (response == null) { + if (headers == null) { throw new IllegalStateException("Could not obtain login URI to retrieve access token from."); } + List wwwAuthenticates = headers.get(WWW_AUTHENTICATE); Map challengeAttributes - = extractChallengeAttributes(response.getFirstHeader(WWW_AUTHENTICATE).getValue()); + = extractChallengeAttributes(wwwAuthenticates == null ? null : wwwAuthenticates.get(0)); String scope = challengeAttributes.get("resource"); if (scope != null) { @@ -373,7 +355,7 @@ private static Map extractChallengeAttributes(String authenticat for (String pair : attributes) { String[] keyValue = pair.split("="); - attributeMap.put(keyValue[0].replaceAll("\"", ""), keyValue[1].replaceAll("\"", "")); + attributeMap.put(keyValue[0].replace("\"", ""), keyValue[1].replace("\"", "")); } LOGGER.exiting("AccessTokenUtil", "extractChallengeAttributes", attributeMap); @@ -391,7 +373,7 @@ private static Map extractChallengeAttributes(String authenticat private static boolean isBearerChallenge(String authenticateHeader) { return authenticateHeader != null && !authenticateHeader.isEmpty() - && authenticateHeader.toLowerCase(Locale.ROOT).startsWith(BEARER_TOKEN_PREFIX.toLowerCase(Locale.ROOT)); + && BEARER_TOKEN_PREFIX.regionMatches(true, 0, authenticateHeader, 0, BEARER_TOKEN_PREFIX.length()); } /** diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/CertificateUtil.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/CertificateUtil.java index 014513520a84..1e64d9dbb0ec 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/CertificateUtil.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/CertificateUtil.java @@ -26,7 +26,6 @@ import java.util.ArrayList; import java.util.Base64; import java.util.List; -import java.util.stream.Collectors; public final class CertificateUtil { private static final String BEGIN_CERTIFICATE = "-----BEGIN CERTIFICATE-----"; @@ -98,11 +97,7 @@ public static Certificate loadX509CertificateFromFile(InputStream inputStream) t public static Certificate[] loadX509CertificatesFromFile(InputStream inputStream) throws CertificateException { CertificateFactory factory = CertificateFactory.getInstance("X.509"); - return factory.generateCertificates(inputStream) - .stream() - .map(o -> (Certificate) o) - .collect(Collectors.toList()) - .toArray(new Certificate[0]); + return factory.generateCertificates(inputStream).toArray(new Certificate[0]); } public static String getCertificateNameFromCertificateItemId(String id) { diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/HttpUtil.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/HttpUtil.java index 4f4480cc0d52..8bd2682d2ece 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/HttpUtil.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/HttpUtil.java @@ -3,34 +3,25 @@ package com.azure.security.keyvault.jca.implementation.utils; import com.azure.security.keyvault.jca.implementation.JreKeyStoreFactory; -import org.apache.hc.client5.http.classic.methods.HttpGet; -import org.apache.hc.client5.http.classic.methods.HttpPost; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; -import org.apache.hc.client5.http.socket.ConnectionSocketFactory; -import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory; -import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; -import org.apache.hc.core5.http.ClassicHttpResponse; -import org.apache.hc.core5.http.ContentType; -import org.apache.hc.core5.http.HttpEntity; -import org.apache.hc.core5.http.config.RegistryBuilder; -import org.apache.hc.core5.http.io.HttpClientResponseHandler; -import org.apache.hc.core5.http.io.entity.EntityUtils; -import org.apache.hc.core5.http.io.entity.StringEntity; -import org.apache.hc.core5.ssl.SSLContexts; - -import javax.net.ssl.HostnameVerifier; + +import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; import java.security.KeyManagementException; -import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.logging.Logger; @@ -59,27 +50,26 @@ public final class HttpUtil { private static final Logger LOGGER = Logger.getLogger(HttpUtil.class.getName()); public static String get(String uri, Map headers) { - String result = null; - - try (CloseableHttpClient client = buildClient()) { - HttpGet httpGet = new HttpGet(uri); + HttpURLConnection connection = null; + try { + connection = openConnection(uri); + connection.setRequestMethod("GET"); + connection.setDoOutput(true); if (headers != null) { - headers.forEach(httpGet::addHeader); + headers.forEach(connection::setRequestProperty); } + connection.setRequestProperty(USER_AGENT_KEY, USER_AGENT_VALUE); - httpGet.addHeader(USER_AGENT_KEY, USER_AGENT_VALUE); - - result = client.execute(httpGet, createResponseHandler()); + return readResponseBody(connection); } catch (IOException ioe) { LOGGER.log(WARNING, "Unable to finish the HTTP GET request.", ioe); + return null; + } finally { + if (connection != null) { + connection.disconnect(); + } } - - return result; - } - - public static String post(String uri, String body, String contentType) { - return post(uri, null, body, contentType); } public static String getUserAgentPrefix() { @@ -95,98 +85,105 @@ public static String getUserAgentPrefix() { } public static String post(String uri, Map headers, String body, String contentType) { - String result = null; - - try (CloseableHttpClient client = buildClient()) { - HttpPost httpPost = new HttpPost(uri); - - httpPost.addHeader(USER_AGENT_KEY, USER_AGENT_VALUE); + HttpURLConnection connection = null; + try { + connection = openConnection(uri); + connection.setRequestMethod("POST"); + connection.setDoOutput(true); if (headers != null) { - headers.forEach(httpPost::addHeader); - httpPost.addHeader("Content-Type", contentType); + headers.forEach(connection::setRequestProperty); + } + if (contentType != null) { + connection.setRequestProperty("Content-Type", contentType); + } + connection.setRequestProperty(USER_AGENT_KEY, USER_AGENT_VALUE); + try (OutputStream outputStream = connection.getOutputStream()) { + outputStream.write(body.getBytes(StandardCharsets.UTF_8)); } - httpPost.setEntity(new StringEntity(body, ContentType.create(contentType))); - - result = client.execute(httpPost, createResponseHandler()); + int status = connection.getResponseCode(); + if (status >= 200 && status < 300) { + return readResponseBody(connection); + } else { + LOGGER.log(SEVERE, createErrorMessage(status)); + return ""; + } } catch (IOException ioe) { LOGGER.log(WARNING, "Unable to finish the HTTP POST request.", ioe); + return null; + } finally { + if (connection != null) { + connection.disconnect(); + } } - - return result; } - public static ClassicHttpResponse getWithResponse(String uri, Map headers) { - ClassicHttpResponse result = null; - - try (CloseableHttpClient client = buildClient()) { - HttpGet httpGet = new HttpGet(uri); - - if (headers != null) { - headers.forEach(httpGet::addHeader); - } + private static String createErrorMessage(int status) { + return "Fail to get response from Key Vault because return http status code is " + status + ". It can be " + + "caused by missing permissions or roles. To know how to add permissions or roles, see " + + "https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/keyvault/azure-security-keyvault-jca#prerequisites."; + } - httpGet.addHeader(USER_AGENT_KEY, USER_AGENT_VALUE); + @SuppressWarnings("StringOperationCanBeSimplified") + private static String readResponseBody(HttpURLConnection connection) throws IOException { + InputStream responseBody + = (connection.getInputStream() != null) ? connection.getInputStream() : connection.getErrorStream(); - result = client.execute(httpGet, createResponseHandlerForAuthChallenge()); - } catch (IOException ioe) { - LOGGER.log(WARNING, "Unable to finish the HTTP GET request.", ioe); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int read; + while ((read = responseBody.read(buffer)) != -1) { + outputStream.write(buffer, 0, read); } - return result; + return new String(outputStream.toByteArray(), StandardCharsets.UTF_8); } - private static HttpClientResponseHandler createResponseHandler() { - return (ClassicHttpResponse response) -> { - int status = response.getCode(); - String result; + public static Map> getWithResponseHeadersOnlyReturn(String uri) { + HttpURLConnection connection = null; + try { + connection = openConnection(uri); + connection.setRequestMethod("GET"); + connection.setDoOutput(true); - if (status >= 200 && status < 300) { - HttpEntity entity = response.getEntity(); - result = entity != null ? EntityUtils.toString(entity) : null; + connection.setRequestProperty(USER_AGENT_KEY, USER_AGENT_VALUE); + + if (connection.getResponseCode() == 401) { + return null; } else { - String errorMessage = "Fail to get response from Key Vault because return http status code is " + status - + ". It " - + "can be caused by missing permissions or roles. To know how to add permissions or roles, see " - + "https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/keyvault/azure-security-keyvault-jca#prerequisites."; - LOGGER.log(SEVERE, errorMessage); - throw new RuntimeException(errorMessage); + return connection.getHeaderFields(); } - - return result; - }; - } - - private static HttpClientResponseHandler createResponseHandlerForAuthChallenge() { - return (ClassicHttpResponse response) -> { - int status = response.getCode(); - - return status == 401 ? response : null; - }; + } catch (IOException ioe) { + LOGGER.log(WARNING, "Unable to finish the HTTP GET request.", ioe); + return null; + } finally { + if (connection != null) { + connection.disconnect(); + } + } } - private static CloseableHttpClient buildClient() { - KeyStore keyStore = JreKeyStoreFactory.getDefaultKeyStore(); - - SSLContext sslContext = null; - + private static HttpURLConnection openConnection(String uri) { try { - sslContext = SSLContexts.custom().loadTrustMaterial(keyStore, null).build(); - } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) { - LOGGER.log(WARNING, "Unable to build the SSL context.", e); - } - - SSLConnectionSocketFactory sslConnectionSocketFactory - = new SSLConnectionSocketFactory(sslContext, (HostnameVerifier) null); - - PoolingHttpClientConnectionManager manager - = new PoolingHttpClientConnectionManager(RegistryBuilder.create() - .register("http", PlainConnectionSocketFactory.getSocketFactory()) - .register("https", sslConnectionSocketFactory) - .build()); + HttpURLConnection connection = (HttpURLConnection) URI.create(uri).toURL().openConnection(); + if (connection instanceof HttpsURLConnection) { + try { + TrustManagerFactory trustManagerFactory + = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(JreKeyStoreFactory.getDefaultKeyStore()); + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, trustManagerFactory.getTrustManagers(), null); + ((HttpsURLConnection) connection).setSSLSocketFactory(sslContext.getSocketFactory()); + } catch (KeyManagementException | KeyStoreException | NoSuchAlgorithmException e) { + LOGGER.log(WARNING, "Unable to build the SSL context.", e); + } + } - return HttpClients.custom().setConnectionManager(manager).build(); + return connection; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } } public static String validateUri(String uri, String propertyName) { diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/JsonConverterUtil.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/JsonConverterUtil.java index 74ebebed0b6b..e40d76a9aa29 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/JsonConverterUtil.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/JsonConverterUtil.java @@ -6,10 +6,8 @@ import com.azure.json.JsonProviders; import com.azure.json.JsonReader; import com.azure.json.JsonSerializable; -import com.azure.json.JsonWriter; import com.azure.json.ReadValueCallback; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.logging.Logger; @@ -55,27 +53,19 @@ public static > T fromJson(ReadValueCallback jsonSerializable) { LOGGER.entering("JsonConverterUtil", "toJson", jsonSerializable); - - if (jsonSerializable == null) { - return null; - } - - try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - JsonWriter jsonWriter = JsonProviders.createWriter(byteArrayOutputStream)) { - - jsonWriter.writeUntyped(jsonSerializable); - jsonWriter.flush(); - - return byteArrayOutputStream.toString("UTF-8"); - } catch (IOException e) { - LOGGER.log(WARNING, "Unable to convert to JSON", e); + String value = null; + + if (jsonSerializable != null) { + try { + value = jsonSerializable.toJsonString(); + } catch (IOException e) { + LOGGER.log(WARNING, "Unable to convert to JSON", e); + } } LOGGER.exiting("JsonConverterUtil", "toJson"); - - return null; + return value; } } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/PropertyConvertorUtils.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/PropertyConvertorUtils.java index b3ca277b5c54..ea0ca7889286 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/PropertyConvertorUtils.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/PropertyConvertorUtils.java @@ -3,7 +3,6 @@ package com.azure.security.keyvault.jca; -import com.azure.core.util.Configuration; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -14,9 +13,6 @@ import java.util.List; public class PropertyConvertorUtils { - - private static final Configuration GLOBAL_CONFIGURATION = Configuration.getGlobalConfiguration(); - public static void putEnvironmentPropertyToSystemPropertyForKeyVaultJca() { KEYVAULT_JCA_SYSTEM_PROPERTIES.forEach(environmentPropertyKey -> { String value = getPropertyValue(environmentPropertyKey); @@ -41,11 +37,12 @@ public static void addKeyVaultJcaProvider() { } public static String getPropertyValue(String property) { - return GLOBAL_CONFIGURATION.get(property, System.getenv(property)); - } + String value = System.getProperty(property); + if (value != null) { + return value; + } - public static String getPropertyValue(String property, String defaultValue) { - return GLOBAL_CONFIGURATION.get(property, defaultValue); + return System.getenv(property); } } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/JreKeyStoreFactoryTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/JreKeyStoreFactoryTest.java index d059a06792f9..21616730cc9e 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/JreKeyStoreFactoryTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/JreKeyStoreFactoryTest.java @@ -7,12 +7,12 @@ import java.security.KeyStore; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; public class JreKeyStoreFactoryTest { @Test public void test() { KeyStore jreKeyStore = JreKeyStoreFactory.getDefaultKeyStore(); - assertFalse(jreKeyStore.getType().equals(KeyVaultKeyStore.KEY_STORE_TYPE)); + assertNotEquals(KeyVaultKeyStore.KEY_STORE_TYPE, jreKeyStore.getType()); } } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/JreKeyStoreTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/JreKeyStoreTest.java index cfa223e5073d..f8152bd1a1b0 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/JreKeyStoreTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/JreKeyStoreTest.java @@ -5,9 +5,12 @@ import com.azure.security.keyvault.jca.implementation.certificates.JreCertificates; import org.junit.jupiter.api.Test; + import java.security.cert.Certificate; import java.util.Map; -import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class JreKeyStoreTest { @@ -17,7 +20,7 @@ public void testJreKsEntries() { assertNotNull(jreCertificates); assertNotNull(jreCertificates.getAliases()); Map certs = jreCertificates.getCertificates(); - assertTrue(certs.size() > 0); + assertFalse(certs.isEmpty()); assertNotNull(jreCertificates.getCertificateKeys()); } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java index 2791d1742e6a..e4dc803d6cc2 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java @@ -52,10 +52,10 @@ public void testGetCertificate() { @Test public void testRefreshAndGetAliasByCertificate() { - Assertions.assertEquals(keyVaultCertificates.refreshAndGetAliasByCertificate(certificate), "myalias"); + Assertions.assertEquals("myalias", keyVaultCertificates.refreshAndGetAliasByCertificate(certificate)); Assertions.assertEquals(keyVaultCertificates.getCertificates().get("myalias"), certificate); when(keyVaultClient.getAliases()).thenReturn(null); - Assertions.assertNotEquals(keyVaultCertificates.refreshAndGetAliasByCertificate(certificate), "myalias"); + Assertions.assertNotEquals("myalias", keyVaultCertificates.refreshAndGetAliasByCertificate(certificate)); Assertions.assertNull(keyVaultCertificates.getCertificates().get("myalias")); } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/SpecificPathCertificatesTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/SpecificPathCertificatesTest.java index 3a038616a521..687ab4700736 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/SpecificPathCertificatesTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/SpecificPathCertificatesTest.java @@ -6,13 +6,15 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.nio.file.FileSystems; + public class SpecificPathCertificatesTest { SpecificPathCertificates specificPathCertificates; public static String getFilePath(String packageName) { String filepath = "\\src\\test\\resources\\" + packageName; - return System.getProperty("user.dir") + filepath.replace("\\", System.getProperty("file.separator")); + return System.getProperty("user.dir") + filepath.replace("\\", FileSystems.getDefault().getSeparator()); } @Test diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSignatureTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSignatureTest.java index 2dbc7d4482a8..24817ae6ac9f 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSignatureTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSignatureTest.java @@ -4,8 +4,8 @@ package com.azure.security.keyvault.jca.implementation.signature; import com.azure.security.keyvault.jca.KeyVaultEncode; -import com.azure.security.keyvault.jca.implementation.KeyVaultPrivateKey; import com.azure.security.keyvault.jca.implementation.KeyVaultClient; +import com.azure.security.keyvault.jca.implementation.KeyVaultPrivateKey; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -14,7 +14,8 @@ import java.security.PrivateKey; import java.security.PublicKey; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/HttpUtilTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/HttpUtilTest.java index d50c99d7a68e..e18044f29d10 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/HttpUtilTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/HttpUtilTest.java @@ -8,7 +8,9 @@ import static com.azure.security.keyvault.jca.implementation.utils.HttpUtil.DEFAULT_USER_AGENT_VALUE_PREFIX; import static com.azure.security.keyvault.jca.implementation.utils.HttpUtil.VERSION; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class HttpUtilTest { diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/JsonConverterUtilTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/JsonConverterUtilTest.java index 8c3639174e81..02fcb0ec516f 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/JsonConverterUtilTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/JsonConverterUtilTest.java @@ -52,7 +52,7 @@ public void testToJson() { @Test void testFromJsonWithTokenResponseBody() { - AccessToken accessToken = null; + AccessToken accessToken; try { accessToken = JsonConverterUtil.fromJson(AccessToken::fromJson, DUMMY_TOKEN_RESPONSE_BODY); } catch (IOException e) { From 607ca6f723a2e4ee6013fb54216ce627a70e0d37 Mon Sep 17 00:00:00 2001 From: alzimmermsft <48699787+alzimmermsft@users.noreply.github.com> Date: Fri, 6 Feb 2026 15:07:06 -0500 Subject: [PATCH 2/7] Finalize work --- .../azure-security-keyvault-jca/README.md | 108 +++++------ .../azure-security-keyvault-jca/pom.xml | 7 + .../KeyVaultKeylessEcSha256Signature.java | 2 +- .../KeyVaultKeylessEcSha384Signature.java | 2 +- .../KeyVaultKeylessEcSha512Signature.java | 2 +- .../KeyVaultKeylessRsa256Signature.java | 2 +- .../KeyVaultKeylessRsa512Signature.java | 2 +- .../KeyVaultKeylessRsaSsaPssSignature.java | 2 +- .../jca/implementation/utils/HttpUtil.java | 2 +- .../security/keyvault/jca/SampleUtils.java | 98 ++++++++++ .../jca/TrustSelfSignedServerDelegate.java | 50 ++++++ .../keyvault/jca/mtls/ClientMTLSSample.java | 66 ++++--- .../keyvault/jca/mtls/ServerMTLSSample.java | 5 +- .../keyvault/jca/tls/ClientSSLSample.java | 63 +++---- .../keyvault/jca/tls/ServerSSLSample.java | 5 +- .../security/keyvault/jca/JcaTestUtils.java | 168 ++++++++++++++++++ .../keyvault/jca/JreKeyStoreTest.java | 49 ++--- .../keyvault/jca/KeyVaultEncodeTest.java | 50 +++--- .../jca/KeyVaultKeyStoreUnitTest.java | 6 +- .../keyvault/jca/ServerSocketTest.java | 80 +++------ .../jca/SpecificPathCertificatesTest.java | 3 +- .../ClasspathCertificatesTest.java | 9 +- .../KeyVaultCertificatesTest.java | 58 ++++-- .../mocking/MockCertificate.java | 48 +++++ .../jca/implementation/mocking/MockKey.java | 22 +++ .../mocking/MockKeyVaultClient.java | 11 ++ .../mocking/MockPrivateKey.java | 22 +++ .../implementation/mocking/MockPublicKey.java | 22 +++ .../KeyVaultKeylessEcSignatureTest.java | 70 +++----- ...KeyVaultKeylessRsaSsaPssSignatureTest.java | 64 ++----- .../utils/JsonConverterUtilTest.java | 20 +-- 31 files changed, 739 insertions(+), 379 deletions(-) create mode 100644 sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/SampleUtils.java create mode 100644 sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/TrustSelfSignedServerDelegate.java create mode 100644 sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/JcaTestUtils.java create mode 100644 sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockCertificate.java create mode 100644 sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockKey.java create mode 100644 sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockKeyVaultClient.java create mode 100644 sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockPrivateKey.java create mode 100644 sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockPublicKey.java diff --git a/sdk/keyvault/azure-security-keyvault-jca/README.md b/sdk/keyvault/azure-security-keyvault-jca/README.md index 90dbff7311f1..c34e16fbcb71 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/README.md +++ b/sdk/keyvault/azure-security-keyvault-jca/README.md @@ -131,8 +131,8 @@ while (true) { BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); String body = "Hello, this is server."; - String response = - "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: " + body.getBytes("UTF-8").length + "\r\n" + "Connection: close\r\n" + "\r\n" + body; + String response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: " + + body.getBytes(StandardCharsets.UTF_8).length + "\r\nConnection: close\r\n\r\n" + body; out.write(response); out.flush(); @@ -156,34 +156,35 @@ Security.addProvider(provider); KeyStore keyStore = KeyVaultKeyStore.getKeyVaultKeyStoreBySystemProperty(); -SSLContext sslContext = SSLContexts - .custom() - .loadTrustMaterial(keyStore, new TrustSelfSignedStrategy()) - .build(); - -SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory( - sslContext, (hostname, session) -> true); - -PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager( - RegistryBuilder.create() - .register("https", sslConnectionSocketFactory) - .build()); +// This section initializing SSLContext can be replaced with implementation specific consumption of 'KeyStore', +// if the library being used has convenience methods for that. +SSLContext sslContext = SSLContext.getInstance("TLS"); +TrustManager[] trustManagers = SampleUtils.loadTrustMaterial(keyStore); +sslContext.init(null, trustManagers, null); String result = null; - -try (CloseableHttpClient client = HttpClients.custom().setConnectionManager(manager).build()) { - HttpGet httpGet = new HttpGet("https://localhost:8765"); - HttpClientResponseHandler responseHandler = (ClassicHttpResponse response) -> { - int status = response.getCode(); - String result1 = "Not success"; - if (status == 200) { - result1 = EntityUtils.toString(response.getEntity()); - } - return result1; - }; - result = client.execute(httpGet, responseHandler); +HttpsURLConnection connection = null; +try { + // openConnection will return HttpsURLConnection when the protocol is 'https'. + connection = (HttpsURLConnection) URI.create("https://localhost:8765").toURL().openConnection(); + + // Have the HttpsURLConnection use the SSLSocketFactory returned by SSLContext. + connection.setSSLSocketFactory(sslContext.getSocketFactory()); + + connection.setRequestMethod("GET"); + int status = connection.getResponseCode(); + if (status == 200) { + result = SampleUtils.readResponse(connection); + } else { + result = "Not success"; + } } catch (IOException ioe) { ioe.printStackTrace(); + result = "Not success"; +} finally { + if (connection != null) { + connection.disconnect(); + } } System.out.println(result); ``` @@ -229,8 +230,8 @@ while (true) { BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); String body = "Hello, this is server."; - String response = - "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: " + body.getBytes("UTF-8").length + "\r\n" + "Connection: close\r\n" + "\r\n" + body; + String response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: " + + body.getBytes(StandardCharsets.UTF_8).length + "\r\nConnection: close\r\n\r\n" + body; out.write(response); out.flush(); @@ -259,35 +260,36 @@ System.setProperty("azure.keyvault.client-id", ""); KeyStore trustStore = KeyVaultKeyStore.getKeyVaultKeyStoreBySystemProperty(); -SSLContext sslContext = SSLContexts - .custom() - .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) - .loadKeyMaterial(keyStore, "".toCharArray()) - .build(); - -SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory( - sslContext, (hostname, session) -> true); - -PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager( - RegistryBuilder.create() - .register("https", sslConnectionSocketFactory) - .build()); +// This section initializing SSLContext can be replaced with implementation specific consumption of 'KeyStore', +// if the library being used has convenience methods for that. +SSLContext sslContext = SSLContext.getInstance("TLS"); +TrustManager[] trustManagers = SampleUtils.loadTrustMaterial(keyStore); +KeyManager[] keyManagers = SampleUtils.loadKeyMaterial(keyStore, "".toCharArray()); +sslContext.init(keyManagers, trustManagers, null); String result = null; - -try (CloseableHttpClient client = HttpClients.custom().setConnectionManager(manager).build()) { - HttpGet httpGet = new HttpGet("https://localhost:8765"); - HttpClientResponseHandler responseHandler = (ClassicHttpResponse response) -> { - int status = response.getCode(); - String result1 = "Not success"; - if (status == 200) { - result1 = EntityUtils.toString(response.getEntity()); - } - return result1; - }; - result = client.execute(httpGet, responseHandler); +HttpsURLConnection connection = null; +try { + // openConnection will return HttpsURLConnection when the protocol is 'https'. + connection = (HttpsURLConnection) URI.create("https://localhost:8765").toURL().openConnection(); + + // Have the HttpsURLConnection use the SSLSocketFactory returned by SSLContext. + connection.setSSLSocketFactory(sslContext.getSocketFactory()); + + connection.setRequestMethod("GET"); + int status = connection.getResponseCode(); + if (status == 200) { + result = SampleUtils.readResponse(connection); + } else { + result = "Not success"; + } } catch (IOException ioe) { ioe.printStackTrace(); + result = "Not success"; +} finally { + if (connection != null) { + connection.disconnect(); + } } System.out.println(result); ``` diff --git a/sdk/keyvault/azure-security-keyvault-jca/pom.xml b/sdk/keyvault/azure-security-keyvault-jca/pom.xml index d480be761abe..078b5409ca46 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/pom.xml +++ b/sdk/keyvault/azure-security-keyvault-jca/pom.xml @@ -76,6 +76,13 @@ 1.17.7 test + + + com.github.spotbugs + spotbugs-annotations + 4.8.3 + test + org.junit.jupiter diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha256Signature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha256Signature.java index be8bf32deea7..564a66586518 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha256Signature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha256Signature.java @@ -9,7 +9,7 @@ public final class KeyVaultKeylessEcSha256Signature extends KeyVaultKeylessEcSig /** * Algorithm name used by this implementation. */ - public static String ALGORITHM_NAME = "SHA256withECDSA"; + public static final String ALGORITHM_NAME = "SHA256withECDSA"; @Override public String getAlgorithmName() { diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha384Signature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha384Signature.java index 9e54533b6dac..81eea1c06d32 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha384Signature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha384Signature.java @@ -9,7 +9,7 @@ public final class KeyVaultKeylessEcSha384Signature extends KeyVaultKeylessEcSig /** * Algorithm name used by this implementation. */ - public static String ALGORITHM_NAME = "SHA384withECDSA"; + public static final String ALGORITHM_NAME = "SHA384withECDSA"; @Override public String getAlgorithmName() { diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha512Signature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha512Signature.java index a468501c1e18..4accc59c0b15 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha512Signature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSha512Signature.java @@ -9,7 +9,7 @@ public final class KeyVaultKeylessEcSha512Signature extends KeyVaultKeylessEcSig /** * Algorithm name used by this implementation. */ - public static String ALGORITHM_NAME = "SHA512withECDSA"; + public static final String ALGORITHM_NAME = "SHA512withECDSA"; @Override public String getAlgorithmName() { diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa256Signature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa256Signature.java index d73051353419..525be4c4f64a 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa256Signature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa256Signature.java @@ -10,7 +10,7 @@ public class KeyVaultKeylessRsa256Signature extends KeyVaultKeylessRsaSignature /** * Algorithm name used by this implementation. */ - public static String ALGORITHM_NAME = "SHA256withRSA"; + public static final String ALGORITHM_NAME = "SHA256withRSA"; @Override public String getAlgorithmName() { diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa512Signature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa512Signature.java index 4d153405190a..d145aa323cb0 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa512Signature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsa512Signature.java @@ -10,7 +10,7 @@ public class KeyVaultKeylessRsa512Signature extends KeyVaultKeylessRsaSignature /** * Algorithm name used by this implementation. */ - public static String ALGORITHM_NAME = "SHA512withRSA"; + public static final String ALGORITHM_NAME = "SHA512withRSA"; @Override public String getAlgorithmName() { diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignature.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignature.java index 0cd86b6bce05..0cff98ef0d35 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignature.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignature.java @@ -16,7 +16,7 @@ public class KeyVaultKeylessRsaSsaPssSignature extends KeyVaultKeylessRsaSignatu /** * Algorithm name used by this implementation. */ - public static String ALGORITHM_NAME = "RSASSA-PSS"; + public static final String ALGORITHM_NAME = "RSASSA-PSS"; @Override public String getAlgorithmName() { diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/HttpUtil.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/HttpUtil.java index 8bd2682d2ece..64ff35f07e24 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/HttpUtil.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/HttpUtil.java @@ -128,7 +128,7 @@ private static String createErrorMessage(int status) { @SuppressWarnings("StringOperationCanBeSimplified") private static String readResponseBody(HttpURLConnection connection) throws IOException { InputStream responseBody - = (connection.getInputStream() != null) ? connection.getInputStream() : connection.getErrorStream(); + = (connection.getErrorStream() != null) ? connection.getErrorStream() : connection.getInputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/SampleUtils.java b/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/SampleUtils.java new file mode 100644 index 000000000000..f280959df1ec --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/SampleUtils.java @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.security.keyvault.jca; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.nio.charset.StandardCharsets; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; + +/** + * Utility methods for samples. + */ +public final class SampleUtils { + /** + * Loads the {@link TrustManager TrustManagers} for the {@link KeyStore}. + *

+ * This wraps {@link X509TrustManager X509TrustManagers} with {@link TrustSelfSignedServerDelegate} to support + * self-signed certificates. + * + * @param keyStore The {@link KeyStore} where {@link TrustManager TrustManagers} will be loaded. + * @return The {@link TrustManager TrustManagers} that were loaded. + * @throws NoSuchAlgorithmException If the algorithm used when calling + * {@link TrustManagerFactory#getInstance(String)} isn't available. + * @throws KeyStoreException If calling {@link TrustManagerFactory#init(KeyStore)} fails. + */ + public static TrustManager[] loadTrustMaterial(KeyStore keyStore) throws NoSuchAlgorithmException, + KeyStoreException { + TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmFactory.init(keyStore); + TrustManager[] trustManagers = tmFactory.getTrustManagers(); + if (trustManagers != null) { + for (int i = 0; i < trustManagers.length; i++) { + TrustManager trustManager = trustManagers[i]; + if (trustManager instanceof X509TrustManager) { + // Wrap X509TrustManagers with an implementation that trusts self-signed certificates. + // This doesn't need to be done and is just an example. + trustManagers[i] = new TrustSelfSignedServerDelegate((X509TrustManager) trustManager); + } + } + } + + return trustManagers; + } + + /** + * Loads the {@link KeyManager KeyManagers} for the {@link KeyStore}. + * + * @param keyStore The {@link KeyStore} where {@link KeyManager KeyManagers} will be loaded. + * @param password The password for recovering {@link KeyManager KeyManagers} in the {@link KeyStore}. + * @return The {@link KeyManager KeyManagers} that were loaded. + * @throws NoSuchAlgorithmException If the algorithm used when calling {@link KeyManagerFactory#getInstance(String)} + * isn't available. + * @throws KeyStoreException If calling {@link KeyManagerFactory#init(KeyStore, char[])} fails. + * @throws UnrecoverableKeyException If the {@link KeyManager} can't be recovered when calling + * {@link KeyManagerFactory#init(KeyStore, char[])}, such as the {@code password is wrong}. + */ + public static KeyManager[] loadKeyMaterial(KeyStore keyStore, char[] password) + throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException { + KeyManagerFactory kmFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmFactory.init(keyStore, password); + return kmFactory.getKeyManagers(); + } + + /** + * Reads the {@link HttpURLConnection} response body to a string. + * + * @param connection The {@link HttpURLConnection} to read the response body for. + * @return The response body as a string. + * @throws IOException If an I/O error occurs while reading the response body. + */ + @SuppressWarnings("StringOperationCanBeSimplified") + public static String readResponse(HttpURLConnection connection) throws IOException { + InputStream response = (connection.getInputStream() != null) + ? connection.getInputStream() + : connection.getErrorStream(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int read; + while ((read = response.read(buffer)) != -1) { + outputStream.write(buffer, 0, read); + } + + return new String(outputStream.toByteArray(), StandardCharsets.UTF_8); + } + + private SampleUtils() { + } +} diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/TrustSelfSignedServerDelegate.java b/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/TrustSelfSignedServerDelegate.java new file mode 100644 index 000000000000..0103ce37b5e3 --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/TrustSelfSignedServerDelegate.java @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.security.keyvault.jca; + +import javax.net.ssl.X509TrustManager; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Objects; + +/** + * Implementation of {@link X509TrustManager} that wraps another {@link X509TrustManager} with a check where self-signed + * server chains are trusted. + *

+ * This implementation uses basic validation for checking if the chain is self-signed, where it only checks that the + * chain has a length of one. This validation only applies when running + * {@link X509TrustManager#checkServerTrusted(X509Certificate[], String)}, and if it passes that method call does not + * delegate to the wrapped {@link X509TrustManager}. + *

+ * {@link X509TrustManager#checkClientTrusted(X509Certificate[], String)} and + * {@link X509TrustManager#getAcceptedIssuers()} always delegate to the wrapped {@link X509TrustManager}. + */ +public final class TrustSelfSignedServerDelegate implements X509TrustManager { + private final X509TrustManager delegate; + + /** + * Creates a new instance of {@link TrustSelfSignedServerDelegate}. + * + * @param delegate The {@link X509TrustManager} that this {@link TrustSelfSignedServerDelegate} will delegate. + */ + public TrustSelfSignedServerDelegate(X509TrustManager delegate) { + this.delegate = Objects.requireNonNull(delegate, "'delegate' cannot be null."); + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + delegate.checkClientTrusted(chain, authType); + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + if (chain.length != 1) { + checkServerTrusted(chain, authType); + } + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return delegate.getAcceptedIssuers(); + } +} diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/mtls/ClientMTLSSample.java b/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/mtls/ClientMTLSSample.java index c4884dbd2ed0..b3f3711b4a6f 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/mtls/ClientMTLSSample.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/mtls/ClientMTLSSample.java @@ -4,21 +4,14 @@ import com.azure.security.keyvault.jca.KeyVaultJcaProvider; import com.azure.security.keyvault.jca.KeyVaultKeyStore; -import org.apache.hc.client5.http.classic.methods.HttpGet; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; -import org.apache.hc.client5.http.socket.ConnectionSocketFactory; -import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; -import org.apache.hc.client5.http.ssl.TrustSelfSignedStrategy; -import org.apache.hc.core5.http.ClassicHttpResponse; -import org.apache.hc.core5.http.config.RegistryBuilder; -import org.apache.hc.core5.http.io.HttpClientResponseHandler; -import org.apache.hc.core5.http.io.entity.EntityUtils; -import org.apache.hc.core5.ssl.SSLContexts; +import com.azure.security.keyvault.jca.SampleUtils; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; import java.io.IOException; +import java.net.URI; import java.security.KeyStore; import java.security.Security; @@ -44,35 +37,36 @@ public static void main(String[] args) throws Exception { System.setProperty("azure.keyvault.client-secret", ""); KeyStore trustStore = KeyVaultKeyStore.getKeyVaultKeyStoreBySystemProperty(); - SSLContext sslContext = SSLContexts - .custom() - .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) - .loadKeyMaterial(keyStore, "".toCharArray()) - .build(); - - SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory( - sslContext, (hostname, session) -> true); - - PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager( - RegistryBuilder.create() - .register("https", sslConnectionSocketFactory) - .build()); + // This section initializing SSLContext can be replaced with implementation specific consumption of 'KeyStore', + // if the library being used has convenience methods for that. + SSLContext sslContext = SSLContext.getInstance("TLS"); + TrustManager[] trustManagers = SampleUtils.loadTrustMaterial(keyStore); + KeyManager[] keyManagers = SampleUtils.loadKeyMaterial(keyStore, "".toCharArray()); + sslContext.init(keyManagers, trustManagers, null); String result = null; + HttpsURLConnection connection = null; + try { + // openConnection will return HttpsURLConnection when the protocol is 'https'. + connection = (HttpsURLConnection) URI.create("https://localhost:8765").toURL().openConnection(); + + // Have the HttpsURLConnection use the SSLSocketFactory returned by SSLContext. + connection.setSSLSocketFactory(sslContext.getSocketFactory()); - try (CloseableHttpClient client = HttpClients.custom().setConnectionManager(manager).build()) { - HttpGet httpGet = new HttpGet("https://localhost:8765"); - HttpClientResponseHandler responseHandler = (ClassicHttpResponse response) -> { - int status = response.getCode(); - String result1 = "Not success"; - if (status == 200) { - result1 = EntityUtils.toString(response.getEntity()); - } - return result1; - }; - result = client.execute(httpGet, responseHandler); + connection.setRequestMethod("GET"); + int status = connection.getResponseCode(); + if (status == 200) { + result = SampleUtils.readResponse(connection); + } else { + result = "Not success"; + } } catch (IOException ioe) { ioe.printStackTrace(); + result = "Not success"; + } finally { + if (connection != null) { + connection.disconnect(); + } } System.out.println(result); // END: readme-sample-clientMTLS diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/mtls/ServerMTLSSample.java b/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/mtls/ServerMTLSSample.java index 119272fa6edd..3f83b02ed56d 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/mtls/ServerMTLSSample.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/mtls/ServerMTLSSample.java @@ -13,6 +13,7 @@ import javax.net.ssl.TrustManagerFactory; import java.io.BufferedWriter; import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; import java.security.KeyStore; import java.security.Security; @@ -57,8 +58,8 @@ public static void main(String[] args) throws Exception { BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); String body = "Hello, this is server."; - String response = - "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: " + body.getBytes("UTF-8").length + "\r\n" + "Connection: close\r\n" + "\r\n" + body; + String response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: " + + body.getBytes(StandardCharsets.UTF_8).length + "\r\nConnection: close\r\n\r\n" + body; out.write(response); out.flush(); diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/tls/ClientSSLSample.java b/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/tls/ClientSSLSample.java index 5e0d4205ce2a..cf7d49a6f202 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/tls/ClientSSLSample.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/tls/ClientSSLSample.java @@ -4,21 +4,13 @@ import com.azure.security.keyvault.jca.KeyVaultJcaProvider; import com.azure.security.keyvault.jca.KeyVaultKeyStore; -import org.apache.hc.client5.http.classic.methods.HttpGet; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; -import org.apache.hc.client5.http.socket.ConnectionSocketFactory; -import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; -import org.apache.hc.client5.http.ssl.TrustSelfSignedStrategy; -import org.apache.hc.core5.http.ClassicHttpResponse; -import org.apache.hc.core5.http.config.RegistryBuilder; -import org.apache.hc.core5.http.io.HttpClientResponseHandler; -import org.apache.hc.core5.http.io.entity.EntityUtils; -import org.apache.hc.core5.ssl.SSLContexts; +import com.azure.security.keyvault.jca.SampleUtils; +import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; import java.io.IOException; +import java.net.URI; import java.security.KeyStore; import java.security.Security; @@ -39,34 +31,35 @@ public static void main(String[] args) throws Exception { KeyStore keyStore = KeyVaultKeyStore.getKeyVaultKeyStoreBySystemProperty(); - SSLContext sslContext = SSLContexts - .custom() - .loadTrustMaterial(keyStore, new TrustSelfSignedStrategy()) - .build(); - - SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory( - sslContext, (hostname, session) -> true); - - PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager( - RegistryBuilder.create() - .register("https", sslConnectionSocketFactory) - .build()); + // This section initializing SSLContext can be replaced with implementation specific consumption of 'KeyStore', + // if the library being used has convenience methods for that. + SSLContext sslContext = SSLContext.getInstance("TLS"); + TrustManager[] trustManagers = SampleUtils.loadTrustMaterial(keyStore); + sslContext.init(null, trustManagers, null); String result = null; + HttpsURLConnection connection = null; + try { + // openConnection will return HttpsURLConnection when the protocol is 'https'. + connection = (HttpsURLConnection) URI.create("https://localhost:8765").toURL().openConnection(); + + // Have the HttpsURLConnection use the SSLSocketFactory returned by SSLContext. + connection.setSSLSocketFactory(sslContext.getSocketFactory()); - try (CloseableHttpClient client = HttpClients.custom().setConnectionManager(manager).build()) { - HttpGet httpGet = new HttpGet("https://localhost:8765"); - HttpClientResponseHandler responseHandler = (ClassicHttpResponse response) -> { - int status = response.getCode(); - String result1 = "Not success"; - if (status == 200) { - result1 = EntityUtils.toString(response.getEntity()); - } - return result1; - }; - result = client.execute(httpGet, responseHandler); + connection.setRequestMethod("GET"); + int status = connection.getResponseCode(); + if (status == 200) { + result = SampleUtils.readResponse(connection); + } else { + result = "Not success"; + } } catch (IOException ioe) { ioe.printStackTrace(); + result = "Not success"; + } finally { + if (connection != null) { + connection.disconnect(); + } } System.out.println(result); // END: readme-sample-clientSSL diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/tls/ServerSSLSample.java b/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/tls/ServerSSLSample.java index f925dd04a75c..491c8113c4ae 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/tls/ServerSSLSample.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/samples/java/com/azure/security/keyvault/jca/tls/ServerSSLSample.java @@ -12,6 +12,7 @@ import javax.net.ssl.SSLSocket; import java.io.BufferedWriter; import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; import java.security.KeyStore; import java.security.Security; @@ -47,8 +48,8 @@ public static void main(String[] args) throws Exception { BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); String body = "Hello, this is server."; - String response = - "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: " + body.getBytes("UTF-8").length + "\r\n" + "Connection: close\r\n" + "\r\n" + body; + String response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: " + + body.getBytes(StandardCharsets.UTF_8).length + "\r\nConnection: close\r\n\r\n" + body; out.write(response); out.flush(); diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/JcaTestUtils.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/JcaTestUtils.java new file mode 100644 index 000000000000..0014f1b83915 --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/JcaTestUtils.java @@ -0,0 +1,168 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.security.keyvault.jca; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509ExtendedKeyManager; +import javax.net.ssl.X509TrustManager; +import java.net.Socket; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; + +/** + * Utility methods for testing KeyVault JCA. + */ +public final class JcaTestUtils { + /** + * Loads {@link TrustManager TrustManagers}. + * + * @param keyStore The {@link KeyStore}. + * @param trustStrategy An optional predicate that is used to skip calling + * {@link X509TrustManager#checkServerTrusted(X509Certificate[], String)}. + * @return The {@link TrustManager TrustManagers}. + * @throws NoSuchAlgorithmException If the algorithm used when calling + * {@link TrustManagerFactory#getInstance(String)} doesn't exist. + * @throws KeyStoreException If {@link TrustManagerFactory#init(KeyStore)} fails. + */ + public static TrustManager[] loadTrustMaterial(KeyStore keyStore, + BiPredicate trustStrategy) throws NoSuchAlgorithmException, KeyStoreException { + TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmFactory.init(keyStore); + TrustManager[] trustManagers = tmFactory.getTrustManagers(); + + if (trustManagers != null && trustStrategy != null) { + for (int i = 0; i < trustManagers.length; i++) { + TrustManager trustManager = trustManagers[i]; + if (trustManager instanceof X509TrustManager) { + trustManagers[i] = new TrustManagerDelegate((X509TrustManager) trustManager, trustStrategy); + } + } + } + + return trustManagers; + } + + /** + * Loads {@link KeyManager KeyManagers}. + * + * @param keyStore The {@link KeyStore}. + * @param aliasStrategy An optional function to handle aliasing. + * @return The {@link KeyManager KeyManagers}. + * @throws NoSuchAlgorithmException If the algorithm used when calling {@link KeyManagerFactory#getInstance(String)} + * doesn't exist. + * @throws KeyStoreException If {@link KeyManagerFactory#init(KeyStore, char[])} fails. + * @throws UnrecoverableKeyException If the {@link KeyManager} can't be recovered when calling + * {@link KeyManagerFactory#init(KeyStore, char[])}, such as the {@code password is wrong}. + */ + public static KeyManager[] loadKeyMaterial(KeyStore keyStore, char[] password, + BiFunction aliasStrategy) + throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException { + KeyManagerFactory kmFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmFactory.init(keyStore, password); + KeyManager[] keyManagers = kmFactory.getKeyManagers(); + + if (keyManagers != null && aliasStrategy != null) { + for (int i = 0; i < keyManagers.length; i++) { + KeyManager keyManager = keyManagers[i]; + if (keyManager instanceof X509ExtendedKeyManager) { + keyManagers[i] = new KeyManagerDelegate((X509ExtendedKeyManager) keyManager, aliasStrategy); + } + } + } + + return keyManagers; + } + + private static final class TrustManagerDelegate implements X509TrustManager { + private final X509TrustManager delegate; + private final BiPredicate trustStrategy; + + private TrustManagerDelegate(X509TrustManager delegate, BiPredicate trustStrategy) { + this.delegate = delegate; + this.trustStrategy = trustStrategy; + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + delegate.checkClientTrusted(chain, authType); + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + if (!trustStrategy.test(chain, authType)) { + delegate.checkServerTrusted(chain, authType); + } + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return delegate.getAcceptedIssuers(); + } + } + + private static final class KeyManagerDelegate extends X509ExtendedKeyManager { + private final X509ExtendedKeyManager delegate; + private final BiFunction aliasStrategy; + + private KeyManagerDelegate(X509ExtendedKeyManager delegate, + BiFunction aliasStrategy) { + this.delegate = delegate; + this.aliasStrategy = aliasStrategy; + } + + @Override + public String[] getClientAliases(String keyType, Principal[] issuers) { + return delegate.getClientAliases(keyType, issuers); + } + + @Override + public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { + return aliasStrategy.apply(keyType, issuers); + } + + @Override + public String[] getServerAliases(String keyType, Principal[] issuers) { + return delegate.getServerAliases(keyType, issuers); + } + + @Override + public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { + return aliasStrategy.apply(new String[] { keyType }, issuers); + } + + @Override + public X509Certificate[] getCertificateChain(String alias) { + return delegate.getCertificateChain(alias); + } + + @Override + public PrivateKey getPrivateKey(String alias) { + return delegate.getPrivateKey(alias); + } + + @Override + public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) { + return aliasStrategy.apply(keyType, issuers); + } + + @Override + public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { + return aliasStrategy.apply(new String[] { keyType }, issuers); + } + } + + private JcaTestUtils() { + } +} diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/JreKeyStoreTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/JreKeyStoreTest.java index 07b74d695e98..fcca34eb1a77 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/JreKeyStoreTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/JreKeyStoreTest.java @@ -4,29 +4,21 @@ package com.azure.security.keyvault.jca; import com.azure.security.keyvault.jca.implementation.certificates.JreCertificates; -import org.apache.hc.client5.http.classic.methods.HttpGet; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; -import org.apache.hc.client5.http.socket.ConnectionSocketFactory; -import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; -import org.apache.hc.core5.http.ClassicHttpResponse; -import org.apache.hc.core5.http.config.RegistryBuilder; -import org.apache.hc.core5.http.io.HttpClientResponseHandler; -import org.apache.hc.core5.ssl.SSLContexts; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; +import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import java.io.IOException; +import java.net.URI; import java.security.KeyStore; import java.security.cert.Certificate; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; @EnabledIfEnvironmentVariable(named = "AZURE_KEYVAULT_CERTIFICATE_NAME", matches = "myalias") public class JreKeyStoreTest { @@ -48,7 +40,7 @@ public void testJreKsEntries() { assertNotNull(jreCertificates); assertNotNull(jreCertificates.getAliases()); Map certs = jreCertificates.getCertificates(); - assertTrue(certs.size() > 0); + assertFalse(certs.isEmpty()); assertNotNull(jreCertificates.getCertificateKeys()); } @@ -64,33 +56,26 @@ public void testJreKsTrustPeer() throws Exception { * - Create SSL connection factory. * - Set hostname verifier to trust any hostname. */ - - SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(ks, null).build(); - - SSLConnectionSocketFactory sslConnectionSocketFactory - = new SSLConnectionSocketFactory(sslContext, (hostname, session) -> true); - - PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager( - RegistryBuilder.create().register("https", sslConnectionSocketFactory).build()); + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, JcaTestUtils.loadTrustMaterial(ks, null), null); /* * And now execute the test. */ String result = null; - - try (CloseableHttpClient client = HttpClients.custom().setConnectionManager(manager).build()) { - HttpGet httpGet = new HttpGet("https://google.com:443"); - HttpClientResponseHandler responseHandler = (ClassicHttpResponse response) -> { - int status = response.getCode(); - String result1 = null; - if (status == 200) { - result1 = "Success"; - } - return result1; - }; - result = client.execute(httpGet, responseHandler); + HttpsURLConnection connection = null; + try { + connection = (HttpsURLConnection) URI.create("https://google.com:443").toURL().openConnection(); + connection.setRequestMethod("GET"); + if (connection.getResponseCode() == 200) { + result = "Success"; + } } catch (IOException ioe) { ioe.printStackTrace(); + } finally { + if (connection != null) { + connection.disconnect(); + } } /* diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultEncodeTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultEncodeTest.java index d6e783d68224..39943cdb33b5 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultEncodeTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultEncodeTest.java @@ -21,43 +21,43 @@ public void buildLengthBytesTest() { Random random = new Random(); int a = random.nextInt(1 << 7); byte[] result = KeyVaultEncode.buildLengthBytes(TEST_TAG, a); - Assertions.assertEquals(result.length, 2); - Assertions.assertEquals(result[0], TEST_TAG); - Assertions.assertEquals(result[1], (byte) a); + Assertions.assertEquals(2, result.length); + Assertions.assertEquals(TEST_TAG, result[0]); + Assertions.assertEquals((byte) a, result[1]); a = random.nextInt((1 << 8) - (1 << 7)) + (1 << 7); result = KeyVaultEncode.buildLengthBytes(TEST_TAG, a); - Assertions.assertEquals(result.length, 3); - Assertions.assertEquals(result[0], TEST_TAG); - Assertions.assertEquals(result[1], (byte) 0x081); - Assertions.assertEquals(result[2], (byte) a); + Assertions.assertEquals(3, result.length); + Assertions.assertEquals(TEST_TAG, result[0]); + Assertions.assertEquals((byte) 0x081, result[1]); + Assertions.assertEquals((byte) a, result[2]); a = random.nextInt((1 << 16) - (1 << 8)) + (1 << 8); result = KeyVaultEncode.buildLengthBytes(TEST_TAG, a); - Assertions.assertEquals(result.length, 4); - Assertions.assertEquals(result[0], TEST_TAG); - Assertions.assertEquals(result[1], (byte) 0x082); - Assertions.assertEquals(result[2], (byte) (a >> 8)); - Assertions.assertEquals(result[3], (byte) a); + Assertions.assertEquals(4, result.length); + Assertions.assertEquals(TEST_TAG, result[0]); + Assertions.assertEquals((byte) 0x082, result[1]); + Assertions.assertEquals((byte) (a >> 8), result[2]); + Assertions.assertEquals((byte) a, result[3]); a = random.nextInt((1 << 24) - (1 << 16)) + (1 << 16); result = KeyVaultEncode.buildLengthBytes(TEST_TAG, a); - Assertions.assertEquals(result.length, 5); - Assertions.assertEquals(result[0], TEST_TAG); - Assertions.assertEquals(result[1], (byte) 0x083); - Assertions.assertEquals(result[2], (byte) (a >> 16)); - Assertions.assertEquals(result[3], (byte) (a >> 8)); - Assertions.assertEquals(result[4], (byte) a); + Assertions.assertEquals(5, result.length); + Assertions.assertEquals(TEST_TAG, result[0]); + Assertions.assertEquals((byte) 0x083, result[1]); + Assertions.assertEquals((byte) (a >> 16), result[2]); + Assertions.assertEquals((byte) (a >> 8), result[3]); + Assertions.assertEquals((byte) a, result[4]); a = random.nextInt((1 << 30) - (1 << 24)) + (1 << 24); result = KeyVaultEncode.buildLengthBytes(TEST_TAG, a); - Assertions.assertEquals(result.length, 6); - Assertions.assertEquals(result[0], TEST_TAG); - Assertions.assertEquals(result[1], (byte) 0x084); - Assertions.assertEquals(result[2], (byte) (a >> 24)); - Assertions.assertEquals(result[3], (byte) (a >> 16)); - Assertions.assertEquals(result[4], (byte) (a >> 8)); - Assertions.assertEquals(result[5], (byte) a); + Assertions.assertEquals(6, result.length); + Assertions.assertEquals(TEST_TAG, result[0]); + Assertions.assertEquals((byte) 0x084, result[1]); + Assertions.assertEquals((byte) (a >> 24), result[2]); + Assertions.assertEquals((byte) (a >> 16), result[3]); + Assertions.assertEquals((byte) (a >> 8), result[4]); + Assertions.assertEquals((byte) a, result[5]); } @Test diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultKeyStoreUnitTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultKeyStoreUnitTest.java index 9e290eaf45fc..af65bb94e014 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultKeyStoreUnitTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultKeyStoreUnitTest.java @@ -51,12 +51,12 @@ public void testGetRefreshInterval() { System.clearProperty("azure.keyvault.jca.certificates-refresh-interval"); System.clearProperty("azure.keyvault.jca.certificates-refresh-interval-in-ms"); KeyVaultKeyStore keystore = new KeyVaultKeyStore(); - assertEquals(keystore.getRefreshInterval(), 0); + assertEquals(0, keystore.getRefreshInterval()); System.setProperty("azure.keyvault.jca.certificates-refresh-interval", "2000"); keystore = new KeyVaultKeyStore(); - assertEquals(keystore.getRefreshInterval(), 2000); + assertEquals(2000, keystore.getRefreshInterval()); System.setProperty("azure.keyvault.jca.certificates-refresh-interval-in-ms", "1000"); - assertEquals(keystore.getRefreshInterval(), 1000); + assertEquals(1000, keystore.getRefreshInterval()); } @Test diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/ServerSocketTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/ServerSocketTest.java index bd2d91b7f6ad..a83d91e3cb87 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/ServerSocketTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/ServerSocketTest.java @@ -3,36 +3,22 @@ package com.azure.security.keyvault.jca; -import org.apache.hc.client5.http.classic.methods.HttpGet; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; -import org.apache.hc.client5.http.socket.ConnectionSocketFactory; -import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; -import org.apache.hc.client5.http.ssl.TrustSelfSignedStrategy; -import org.apache.hc.core5.http.ClassicHttpResponse; -import org.apache.hc.core5.http.config.RegistryBuilder; -import org.apache.hc.core5.http.io.HttpClientResponseHandler; -import org.apache.hc.core5.ssl.PrivateKeyDetails; -import org.apache.hc.core5.ssl.PrivateKeyStrategy; -import org.apache.hc.core5.ssl.SSLContexts; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; +import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.TrustManagerFactory; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; +import java.net.URI; import java.security.KeyStore; import java.security.Security; -import java.security.cert.X509Certificate; -import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -57,7 +43,7 @@ public static void beforeEach() throws Exception { KeyVaultJcaProvider provider = new KeyVaultJcaProvider(); Security.addProvider(provider); - /** + /* * - Create an Azure Key Vault specific instance of a KeyStore. * - Set the KeyManagerFactory to use that KeyStore. */ @@ -86,16 +72,16 @@ private void startSocket(SSLServerSocket serverSocket) { @Test public void testHttpsConnectionWithoutClientTrust() throws Exception { - SSLContext sslContext = SSLContexts.custom() - .loadTrustMaterial((final X509Certificate[] chain, final String authType) -> true) - .build(); + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, JcaTestUtils.loadTrustMaterial(null, (ignoredChain, ignoredAuthType) -> true), null); testHttpsConnection(8765, sslContext); } @Test public void testHttpsConnectionWithSelfSignedClientTrust() throws Exception { - SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(ks, new TrustSelfSignedStrategy()).build(); + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, JcaTestUtils.loadTrustMaterial(ks, (chain, ignored) -> chain.length == 1), null); testHttpsConnection(8766, sslContext); } @@ -144,7 +130,7 @@ private void testHttpsConnection(Integer port, SSLContext sslContext) throws Exc assertEquals("Success", result); } - private void serverSocketWithTrustManager(Integer port) throws Exception { + private void serverSocketWithTrustManager(int port) throws Exception { /* * Setup server side. * @@ -169,11 +155,10 @@ private void serverSocketWithTrustManager(Integer port) throws Exception { * - Create an SSL context. * - Set SSL context to trust any certificate. */ - - SSLContext sslContext = SSLContexts.custom() - .loadTrustMaterial(ks, new TrustSelfSignedStrategy()) - .loadKeyMaterial(ks, "".toCharArray(), new ClientPrivateKeyStrategy()) - .build(); + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init( + JcaTestUtils.loadKeyMaterial(ks, "".toCharArray(), (ignoredKeyTypes, ignoredIssuers) -> certificateName), + JcaTestUtils.loadTrustMaterial(ks, (chain, ignored) -> chain.length == 1), null); /* * And now execute the test. @@ -186,41 +171,28 @@ private void serverSocketWithTrustManager(Integer port) throws Exception { assertEquals("Success", result); } - private String sendRequest(SSLContext sslContext, Integer port) { + private String sendRequest(SSLContext sslContext, int port) { - /** + /* * - Create SSL connection factory. * - Set hostname verifier to trust any hostname. */ - SSLConnectionSocketFactory sslConnectionSocketFactory - = new SSLConnectionSocketFactory(sslContext, (hostname, session) -> true); - - PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager( - RegistryBuilder.create().register("https", sslConnectionSocketFactory).build()); - String result = null; - - try (CloseableHttpClient client = HttpClients.custom().setConnectionManager(manager).build()) { - HttpGet httpGet = new HttpGet("https://localhost:" + port); - HttpClientResponseHandler responseHandler = (ClassicHttpResponse response) -> { - int status = response.getCode(); - String result1 = null; - if (status == 204) { - result1 = "Success"; - } - return result1; - }; - result = client.execute(httpGet, responseHandler); + HttpsURLConnection connection = null; + try { + connection = (HttpsURLConnection) URI.create("https://localhost:" + port).toURL().openConnection(); + connection.setSSLSocketFactory(sslContext.getSocketFactory()); + connection.setRequestMethod("GET"); + if (connection.getResponseCode() == 204) { + result = "Success"; + } } catch (IOException ioe) { ioe.printStackTrace(); + } finally { + if (connection != null) { + connection.disconnect(); + } } return result; } - - private static class ClientPrivateKeyStrategy implements PrivateKeyStrategy { - @Override - public String chooseAlias(Map aliases, SSLParameters sslParameters) { - return certificateName; // It should be your certificate alias used in client-side - } - } } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/SpecificPathCertificatesTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/SpecificPathCertificatesTest.java index 8932a202a584..dd4e6d5c71a8 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/SpecificPathCertificatesTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/SpecificPathCertificatesTest.java @@ -13,6 +13,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.file.FileSystems; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -35,7 +36,7 @@ public static void setEnvironmentProperty() { public static String getFilePath(String packageName) { String filepath = "\\src\\test\\resources\\" + packageName; - return System.getProperty("user.dir") + filepath.replace("\\", System.getProperty("file.separator")); + return System.getProperty("user.dir") + filepath.replace("\\", FileSystems.getDefault().getSeparator()); } @Test diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/ClasspathCertificatesTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/ClasspathCertificatesTest.java index e2dab5e2f7b1..fed6265ab347 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/ClasspathCertificatesTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/ClasspathCertificatesTest.java @@ -3,15 +3,14 @@ package com.azure.security.keyvault.jca.implementation.certificates; -import static org.mockito.Mockito.mock; - -import java.security.cert.Certificate; +import com.azure.security.keyvault.jca.implementation.mocking.MockCertificate; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -public class ClasspathCertificatesTest { +import java.security.cert.Certificate; - private final Certificate certificate = mock(Certificate.class); +public class ClasspathCertificatesTest { + private final Certificate certificate = new MockCertificate(); @Test public void testSetCertificateEntry() { diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java index e4dc803d6cc2..7e41fa8a92b9 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java @@ -3,35 +3,56 @@ package com.azure.security.keyvault.jca.implementation.certificates; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - import com.azure.security.keyvault.jca.implementation.KeyVaultClient; +import com.azure.security.keyvault.jca.implementation.mocking.MockCertificate; +import com.azure.security.keyvault.jca.implementation.mocking.MockKey; +import com.azure.security.keyvault.jca.implementation.mocking.MockKeyVaultClient; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import java.security.Key; import java.security.cert.Certificate; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; public class KeyVaultCertificatesTest { + private final Key key = new MockKey(); + private final Certificate certificate = new MockCertificate(); - private final KeyVaultClient keyVaultClient = mock(KeyVaultClient.class); - - private final Key key = mock(Key.class); - - private final Certificate certificate = mock(Certificate.class); - + // This needs to be mutable. + private List aliases = new ArrayList<>(Collections.singletonList("myalias")); private KeyVaultCertificates keyVaultCertificates; @BeforeEach public void beforeEach() { - List aliases = new ArrayList<>(); - aliases.add("myalias"); - when(keyVaultClient.getAliases()).thenReturn(aliases); - when(keyVaultClient.getKey("myalias", null)).thenReturn(key); - when(keyVaultClient.getCertificate("myalias")).thenReturn(certificate); + KeyVaultClient keyVaultClient = new MockKeyVaultClient() { + @Override + public List getAliases() { + return aliases; + } + + @Override + public Key getKey(String alias, char[] password) { + return "myalias".equals(alias) && password == null ? key : null; + } + + @Override + public Certificate getCertificate(String alias) { + return "myalias".equals(alias) ? certificate : null; + } + + @Override + public Certificate[] getCertificateChain(String alias) { + return null; + } + + @Override + public byte[] getSignedWithPrivateKey(String digestName, String digestValue, String keyId) { + return null; + } + }; keyVaultCertificates = new KeyVaultCertificates(60_000, keyVaultClient); } @@ -54,7 +75,8 @@ public void testGetCertificate() { public void testRefreshAndGetAliasByCertificate() { Assertions.assertEquals("myalias", keyVaultCertificates.refreshAndGetAliasByCertificate(certificate)); Assertions.assertEquals(keyVaultCertificates.getCertificates().get("myalias"), certificate); - when(keyVaultClient.getAliases()).thenReturn(null); + + this.aliases = null; Assertions.assertNotEquals("myalias", keyVaultCertificates.refreshAndGetAliasByCertificate(certificate)); Assertions.assertNull(keyVaultCertificates.getCertificates().get("myalias")); } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockCertificate.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockCertificate.java new file mode 100644 index 000000000000..b4afd69c7ea9 --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockCertificate.java @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.security.keyvault.jca.implementation.mocking; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; + +/** + * Mock of {@link Certificate}. + */ +public class MockCertificate extends Certificate { + public MockCertificate() { + super("mock"); + } + + @Override + public byte[] getEncoded() throws CertificateEncodingException { + return new byte[0]; + } + + @Override + public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException { + + } + + @Override + public void verify(PublicKey key, String sigProvider) throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException { + + } + + @Override + public String toString() { + return ""; + } + + @Override + public PublicKey getPublicKey() { + return null; + } +} diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockKey.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockKey.java new file mode 100644 index 000000000000..c6021f17dc0f --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockKey.java @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.security.keyvault.jca.implementation.mocking; + +import java.security.Key; + +public class MockKey implements Key { + @Override + public String getAlgorithm() { + return ""; + } + + @Override + public String getFormat() { + return ""; + } + + @Override + public byte[] getEncoded() { + return new byte[0]; + } +} diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockKeyVaultClient.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockKeyVaultClient.java new file mode 100644 index 000000000000..94834e2f2ed2 --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockKeyVaultClient.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.security.keyvault.jca.implementation.mocking; + +import com.azure.security.keyvault.jca.implementation.KeyVaultClient; + +public class MockKeyVaultClient extends KeyVaultClient { + public MockKeyVaultClient() { + super("https://accountname.vault.azure.net", "tenant-id", "client-id", "client-secret"); + } +} diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockPrivateKey.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockPrivateKey.java new file mode 100644 index 000000000000..b0fbd78f676b --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockPrivateKey.java @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.security.keyvault.jca.implementation.mocking; + +import java.security.PrivateKey; + +public class MockPrivateKey implements PrivateKey { + @Override + public String getAlgorithm() { + return null; + } + + @Override + public String getFormat() { + return null; + } + + @Override + public byte[] getEncoded() { + return new byte[0]; + } +} diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockPublicKey.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockPublicKey.java new file mode 100644 index 000000000000..4ee99bb9511e --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockPublicKey.java @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.security.keyvault.jca.implementation.mocking; + +import java.security.PublicKey; + +public class MockPublicKey implements PublicKey { + @Override + public String getAlgorithm() { + return null; + } + + @Override + public String getFormat() { + return null; + } + + @Override + public byte[] getEncoded() { + return new byte[0]; + } +} diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSignatureTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSignatureTest.java index 24817ae6ac9f..5f0685815cd9 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSignatureTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSignatureTest.java @@ -6,30 +6,29 @@ import com.azure.security.keyvault.jca.KeyVaultEncode; import com.azure.security.keyvault.jca.implementation.KeyVaultClient; import com.azure.security.keyvault.jca.implementation.KeyVaultPrivateKey; +import com.azure.security.keyvault.jca.implementation.mocking.MockKeyVaultClient; +import com.azure.security.keyvault.jca.implementation.mocking.MockPrivateKey; +import com.azure.security.keyvault.jca.implementation.mocking.MockPublicKey; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatchers; import java.security.PrivateKey; import java.security.PublicKey; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class KeyVaultKeylessEcSignatureTest { KeyVaultKeylessEcSignature keyVaultKeylessEcSignature; - private final KeyVaultClient keyVaultClient = mock(KeyVaultClient.class); - - private final KeyVaultPrivateKey keyVaultPrivateKey = mock(KeyVaultPrivateKey.class); + private KeyVaultClient keyVaultClient; private final byte[] signedWithES256 = "fake256Value".getBytes(); private final byte[] signedWithES384 = "fake384Value".getBytes(); + private final PublicKey publicKey = new MockPublicKey(); + private final PrivateKey privateKey = new MockPrivateKey(); static final String KEY_VAULT_TEST_URI_GLOBAL = "https://fake.vault.azure.net/"; @@ -39,40 +38,6 @@ public void before() { keyVaultKeylessEcSignature = new KeyVaultKeylessEcSha256Signature(); } - private final PublicKey publicKey = new PublicKey() { - @Override - public String getAlgorithm() { - return null; - } - - @Override - public String getFormat() { - return null; - } - - @Override - public byte[] getEncoded() { - return new byte[0]; - } - }; - - private final PrivateKey privateKey = new PrivateKey() { - @Override - public String getAlgorithm() { - return null; - } - - @Override - public String getFormat() { - return null; - } - - @Override - public byte[] getEncoded() { - return new byte[0]; - } - }; - @Test public void engineInitVerifyTest() { assertThrows(UnsupportedOperationException.class, () -> keyVaultKeylessEcSignature.engineInitVerify(publicKey)); @@ -102,18 +67,31 @@ public void engineSetParameterTest() { @Test public void setDigestNameAndEngineSignTest() { + keyVaultClient = new MockKeyVaultClient() { + @Override + public byte[] getSignedWithPrivateKey(String digestName, String digestValue, String keyId) { + return "ES256".equals(digestName) ? signedWithES256 : null; + } + }; + KeyVaultPrivateKey keyVaultPrivateKey = new KeyVaultPrivateKey("algorithm", "kid") { + @Override + public KeyVaultClient getKeyVaultClient() { + return keyVaultClient; + } + }; keyVaultKeylessEcSignature = new KeyVaultKeylessEcSha256Signature(); - when(keyVaultClient.getSignedWithPrivateKey(ArgumentMatchers.eq("ES256"), anyString(), - ArgumentMatchers.eq(null))).thenReturn(signedWithES256); - when(keyVaultPrivateKey.getKeyVaultClient()).thenReturn(keyVaultClient); keyVaultKeylessEcSignature.engineInitSign(keyVaultPrivateKey, null); Assertions.assertArrayEquals(KeyVaultEncode.encodeByte(signedWithES256), keyVaultKeylessEcSignature.engineSign()); + keyVaultClient = new MockKeyVaultClient() { + @Override + public byte[] getSignedWithPrivateKey(String digestName, String digestValue, String keyId) { + return "ES384".equals(digestName) ? signedWithES384 : null; + } + }; keyVaultKeylessEcSignature = new KeyVaultKeylessEcSha384Signature(); keyVaultKeylessEcSignature.engineInitSign(keyVaultPrivateKey, null); - when(keyVaultClient.getSignedWithPrivateKey(ArgumentMatchers.eq("ES384"), anyString(), - ArgumentMatchers.eq(null))).thenReturn(signedWithES384); assertArrayEquals(KeyVaultEncode.encodeByte(signedWithES384), keyVaultKeylessEcSignature.engineSign()); } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignatureTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignatureTest.java index bda7ae92447b..946f3e35b843 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignatureTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignatureTest.java @@ -3,12 +3,15 @@ package com.azure.security.keyvault.jca.implementation.signature; -import com.azure.security.keyvault.jca.implementation.KeyVaultPrivateKey; import com.azure.security.keyvault.jca.implementation.KeyVaultClient; +import com.azure.security.keyvault.jca.implementation.KeyVaultPrivateKey; +import com.azure.security.keyvault.jca.implementation.mocking.MockKeyVaultClient; +import com.azure.security.keyvault.jca.implementation.mocking.MockPrivateKey; +import com.azure.security.keyvault.jca.implementation.mocking.MockPublicKey; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatchers; +import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.PrivateKey; import java.security.PublicKey; @@ -18,19 +21,15 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class KeyVaultKeylessRsaSsaPssSignatureTest { KeyVaultKeylessRsaSsaPssSignature keyVaultKeylessRsaSsaPssSignature; - static final String KEY_VAULT_TEST_URI_GLOBAL = "https://fake.vault.azure.net/"; - - private final KeyVaultClient keyVaultClient = mock(KeyVaultClient.class); + private final PublicKey publicKey = new MockPublicKey(); + private final PrivateKey privateKey = new MockPrivateKey(); - private final KeyVaultPrivateKey keyVaultPrivateKey = mock(KeyVaultPrivateKey.class); + static final String KEY_VAULT_TEST_URI_GLOBAL = "https://fake.vault.azure.net/"; @BeforeEach public void before() { @@ -38,40 +37,6 @@ public void before() { keyVaultKeylessRsaSsaPssSignature = new KeyVaultKeylessRsaSsaPssSignature(); } - private final PublicKey publicKey = new PublicKey() { - @Override - public String getAlgorithm() { - return null; - } - - @Override - public String getFormat() { - return null; - } - - @Override - public byte[] getEncoded() { - return new byte[0]; - } - }; - - private final PrivateKey privateKey = new PrivateKey() { - @Override - public String getAlgorithm() { - return null; - } - - @Override - public String getFormat() { - return null; - } - - @Override - public byte[] getEncoded() { - return new byte[0]; - } - }; - @Test public void engineInitVerifyTest() { assertThrows(UnsupportedOperationException.class, @@ -103,13 +68,17 @@ public void engineSetParameterTest() { @Test public void setDigestNameAndEngineSignTest() throws InvalidAlgorithmParameterException { + KeyVaultClient keyVaultClient = new MockKeyVaultClient() { + @Override + public byte[] getSignedWithPrivateKey(String digestName, String digestValue, String keyId) { + return "PS256".equals(digestName) ? "fakeValue".getBytes(StandardCharsets.UTF_8) : null; + } + }; + KeyVaultPrivateKey keyVaultPrivateKey = new KeyVaultPrivateKey("algorithm", "kid", keyVaultClient); keyVaultKeylessRsaSsaPssSignature = new KeyVaultKeylessRsaSsaPssSignature(); - when(keyVaultPrivateKey.getKeyVaultClient()).thenReturn(keyVaultClient); keyVaultKeylessRsaSsaPssSignature.engineInitSign(keyVaultPrivateKey, null); keyVaultKeylessRsaSsaPssSignature .engineSetParameter(new PSSParameterSpec("SHA-1", "MGF1", MGF1ParameterSpec.SHA1, 20, 1)); - when(keyVaultClient.getSignedWithPrivateKey(ArgumentMatchers.eq("PS256"), anyString(), - ArgumentMatchers.eq(null))).thenReturn("fakeValue".getBytes()); assertArrayEquals("fakeValue".getBytes(), keyVaultKeylessRsaSsaPssSignature.engineSign()); } @@ -123,7 +92,8 @@ public void engineSetParameterWithNullParameterTest() { @Test public void engineSetParameterWithNotPSSParameterSpecTest() { keyVaultKeylessRsaSsaPssSignature = new KeyVaultKeylessRsaSsaPssSignature(); - AlgorithmParameterSpec algorithmParameterSpec = mock(AlgorithmParameterSpec.class); + AlgorithmParameterSpec algorithmParameterSpec = new AlgorithmParameterSpec() { + }; assertThrows(InvalidAlgorithmParameterException.class, () -> keyVaultKeylessRsaSsaPssSignature.engineSetParameter(algorithmParameterSpec)); } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/JsonConverterUtilTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/JsonConverterUtilTest.java index 02fcb0ec516f..23c13f00f9b1 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/JsonConverterUtilTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/JsonConverterUtilTest.java @@ -8,8 +8,7 @@ import com.azure.security.keyvault.jca.implementation.model.CertificateBundle; import org.junit.jupiter.api.Test; -import java.io.IOException; - +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -27,9 +26,9 @@ public class JsonConverterUtilTest { * Test the {@link JsonConverterUtil#fromJson(ReadValueCallback, String)} method. */ @Test - public void testFromJson() throws IOException { - String string = "{ \"cer\": \"cer\" }"; - CertificateBundle bundle = JsonConverterUtil.fromJson(CertificateBundle::fromJson, string); + public void testFromJson() { + CertificateBundle bundle + = assertDoesNotThrow(() -> JsonConverterUtil.fromJson(CertificateBundle::fromJson, "{\"cer\":\"cer\"}")); assertNotNull(bundle); assertEquals("cer", bundle.getCer()); @@ -41,23 +40,18 @@ public void testFromJson() throws IOException { @Test public void testToJson() { CertificateBundle bundle = new CertificateBundle(); - bundle.setCer("value"); String string = JsonConverterUtil.toJson(bundle); - assertTrue(string.contains("cer")); + assertTrue(string.contains("\"cer\"")); assertTrue(string.contains("\"value\"")); } @Test void testFromJsonWithTokenResponseBody() { - AccessToken accessToken; - try { - accessToken = JsonConverterUtil.fromJson(AccessToken::fromJson, DUMMY_TOKEN_RESPONSE_BODY); - } catch (IOException e) { - throw new RuntimeException(e); - } + AccessToken accessToken + = assertDoesNotThrow(() -> JsonConverterUtil.fromJson(AccessToken::fromJson, DUMMY_TOKEN_RESPONSE_BODY)); assertNotNull(accessToken); assertEquals("test_access_token_value", accessToken.getAccessToken()); } From 8c9c5602044b0c2ced7f7bc8ae734c179e45ec10 Mon Sep 17 00:00:00 2001 From: alzimmermsft <48699787+alzimmermsft@users.noreply.github.com> Date: Fri, 6 Feb 2026 15:26:45 -0500 Subject: [PATCH 3/7] Finalize work --- .../jca/implementation/{mocking => }/MockKeyVaultClient.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/{mocking => }/MockKeyVaultClient.java (100%) diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockKeyVaultClient.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/MockKeyVaultClient.java similarity index 100% rename from sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/mocking/MockKeyVaultClient.java rename to sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/MockKeyVaultClient.java From 32fa6fd5fb05e59b8566ecb70ac3f53b72932450 Mon Sep 17 00:00:00 2001 From: alzimmermsft <48699787+alzimmermsft@users.noreply.github.com> Date: Fri, 6 Feb 2026 15:45:41 -0500 Subject: [PATCH 4/7] Remove Mockito --- .../azure-security-keyvault-jca/pom.xml | 28 -- .../jca/implementation/KeyVaultClient.java | 33 +- .../keyvault/jca/KeyVaultEncodeTest.java | 18 +- .../implementation/KeyVaultClientTest.java | 351 +++++++++--------- .../implementation/MockKeyVaultClient.java | 4 +- .../KeyVaultCertificatesTest.java | 2 +- .../KeyVaultKeylessEcSignatureTest.java | 2 +- ...KeyVaultKeylessRsaSsaPssSignatureTest.java | 2 +- 8 files changed, 215 insertions(+), 225 deletions(-) diff --git a/sdk/keyvault/azure-security-keyvault-jca/pom.xml b/sdk/keyvault/azure-security-keyvault-jca/pom.xml index 078b5409ca46..f469d95f3476 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/pom.xml +++ b/sdk/keyvault/azure-security-keyvault-jca/pom.xml @@ -55,34 +55,6 @@ slf4j-nop 1.7.36 - - - org.mockito - mockito-inline - 4.11.0 - test - - - - - net.bytebuddy - byte-buddy - 1.17.7 - test - - - net.bytebuddy - byte-buddy-agent - 1.17.7 - test - - - - com.github.spotbugs - spotbugs-annotations - 4.8.3 - test - org.junit.jupiter diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java index 725e3c999698..a1e98178d5d8 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java @@ -226,7 +226,7 @@ private AccessToken obtainAccessToken() { // Priority: 1. Managed Identity, 2. Provided Access Token, 3. Client ID/Secret if (managedIdentity != null) { LOGGER.info("Using managed identity for authentication"); - result = AccessTokenUtil.getAccessToken(resource, managedIdentity); + result = getAccessToken(resource, managedIdentity); } else if (providedAccessToken != null && !providedAccessToken.isEmpty()) { LOGGER.info("Using provided access token for authentication"); // Create an AccessToken object from the provided token string @@ -238,8 +238,7 @@ private AccessToken obtainAccessToken() { LOGGER.info("Using client credentials (client ID/secret) for authentication"); String aadAuthenticationUri = getLoginUri(keyVaultUri + "certificates" + API_VERSION_POSTFIX, disableChallengeResourceVerification); - result - = AccessTokenUtil.getAccessToken(resource, aadAuthenticationUri, tenantId, clientId, clientSecret); + result = getAccessToken(resource, aadAuthenticationUri, tenantId, clientId, clientSecret); } } catch (UnsupportedEncodingException e) { LOGGER.log(WARNING, "Could not obtain access token to authenticate with.", e); @@ -263,7 +262,7 @@ public List getAliases() { String uri = keyVaultUri + "certificates" + API_VERSION_POSTFIX; while (uri != null && !uri.isEmpty()) { - String response = HttpUtil.get(uri, headers); + String response = httpGet(uri, headers); CertificateListResult certificateListResult = null; if (response != null) { @@ -301,7 +300,7 @@ private CertificateBundle getCertificateBundle(String alias) { LOGGER.entering("KeyVaultClient", "getCertificateBundle", alias); CertificateBundle result = null; - String response = HttpUtil.get(keyVaultUri + "certificates/" + alias + API_VERSION_POSTFIX, + String response = httpGet(keyVaultUri + "certificates/" + alias + API_VERSION_POSTFIX, Collections.singletonMap("Authorization", "Bearer " + getAccessToken())); if (response != null) { @@ -362,7 +361,7 @@ public Certificate[] getCertificateChain(String alias) { LOGGER.log(INFO, "Getting certificate chain for alias: {0}", alias); String uri = keyVaultUri + "secrets/" + alias + API_VERSION_POSTFIX; - String response = HttpUtil.get(uri, Collections.singletonMap("Authorization", "Bearer " + getAccessToken())); + String response = httpGet(uri, Collections.singletonMap("Authorization", "Bearer " + getAccessToken())); if (response == null) { throw new NullPointerException(); @@ -431,7 +430,7 @@ public Key getKey(String alias, char[] password) { return key; } - String body = HttpUtil.get(certificateBundle.getSid() + API_VERSION_POSTFIX, + String body = httpGet(certificateBundle.getSid() + API_VERSION_POSTFIX, Collections.singletonMap("Authorization", "Bearer " + getAccessToken())); if (body == null) { @@ -504,8 +503,7 @@ public byte[] getSignedWithPrivateKey(String digestName, String digestValue, Str String bodyString = "{\"alg\": \"" + digestName + "\", \"value\": \"" + digestValue + "\"}"; Map headers = Collections.singletonMap("Authorization", "Bearer " + getAccessToken()); - String uri = keyId + "/sign" + API_VERSION_POSTFIX; - String response = HttpUtil.post(uri, headers, bodyString, "application/json"); + String response = httpPost("/sign" + API_VERSION_POSTFIX, headers, bodyString, "application/json"); if (response != null) { try { @@ -579,4 +577,21 @@ private PrivateKey createPrivateKeyFromPem(String pemString, String keyType) return privateKey; } + + String httpGet(String uri, Map headers) { + return HttpUtil.get(uri, headers); + } + + String httpPost(String uri, Map headers, String body, String contentType) { + return HttpUtil.post(uri, headers, body, contentType); + } + + AccessToken getAccessToken(String resource, String identity) { + return AccessTokenUtil.getAccessToken(resource, managedIdentity); + } + + AccessToken getAccessToken(String resource, String aadAuthenticationUri, String tenantId, String clientId, + String clientSecret) { + return AccessTokenUtil.getAccessToken(resource, aadAuthenticationUri, tenantId, clientId, clientSecret); + } } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultEncodeTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultEncodeTest.java index 39943cdb33b5..2e77690995a8 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultEncodeTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultEncodeTest.java @@ -3,11 +3,11 @@ package com.azure.security.keyvault.jca; -import net.bytebuddy.utility.RandomString; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.math.BigInteger; +import java.security.SecureRandom; import java.util.Arrays; import java.util.Base64; import java.util.Random; @@ -62,9 +62,10 @@ public void buildLengthBytesTest() { @Test public void concatBytesWithThreeBytes() { - byte[] byte1 = RandomString.make(32).getBytes(); - byte[] byte2 = RandomString.make(32).getBytes(); - byte[] byte3 = RandomString.make(32).getBytes(); + SecureRandom random = new SecureRandom(); + byte[] byte1 = random.generateSeed(32); + byte[] byte2 = random.generateSeed(32); + byte[] byte3 = random.generateSeed(32); byte[] result = KeyVaultEncode.concatBytes(byte1, byte2, byte3); Assertions.assertArrayEquals(byte1, Arrays.copyOfRange(result, 0, byte1.length)); Assertions.assertArrayEquals(byte2, Arrays.copyOfRange(result, byte1.length, byte1.length + byte2.length)); @@ -73,8 +74,9 @@ public void concatBytesWithThreeBytes() { @Test public void concatBytesWithTwoBytes() { - byte[] byte1 = RandomString.make(32).getBytes(); - byte[] byte2 = RandomString.make(32).getBytes(); + SecureRandom random = new SecureRandom(); + byte[] byte1 = random.generateSeed(32); + byte[] byte2 = random.generateSeed(32); byte[] result = KeyVaultEncode.concatBytes(byte1, byte2); Assertions.assertArrayEquals(byte1, Arrays.copyOfRange(result, 0, byte1.length)); Assertions.assertArrayEquals(byte2, Arrays.copyOfRange(result, byte1.length, result.length)); @@ -82,8 +84,8 @@ public void concatBytesWithTwoBytes() { @Test public void toBigIntegerBytesWithLengthPrefixTest() { - byte[] testByte = RandomString.make(32).getBytes(); - Random random = new Random(); + SecureRandom random = new SecureRandom(); + byte[] testByte = random.generateSeed(32); int offset = random.nextInt(testByte.length); int length = random.nextInt(testByte.length - offset); byte[] result = KeyVaultEncode.toBigIntegerBytesWithLengthPrefix(testByte, offset, length); diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/KeyVaultClientTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/KeyVaultClientTest.java index 22f80900efa6..348f7935192a 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/KeyVaultClientTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/KeyVaultClientTest.java @@ -7,236 +7,239 @@ import com.azure.security.keyvault.jca.implementation.model.AccessToken; import com.azure.security.keyvault.jca.implementation.model.CertificateItem; import com.azure.security.keyvault.jca.implementation.model.CertificateListResult; -import com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil; -import com.azure.security.keyvault.jca.implementation.utils.HttpUtil; import com.azure.security.keyvault.jca.implementation.utils.JsonConverterUtil; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; -import org.mockito.MockedStatic; -import org.mockito.Mockito; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.anyMap; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.notNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; public class KeyVaultClientTest { private static final String KEY_VAULT_TEST_URI_GLOBAL = "https://fake.vault.azure.net/"; @Test public void testGetAliasWithCertificateInfoWith0Page() { - try (MockedStatic utilities = Mockito.mockStatic(HttpUtil.class)) { - utilities.when(() -> HttpUtil.get(anyString(), anyMap())).thenReturn("fakeValue"); - - KeyVaultClient keyVaultClient = mock(KeyVaultClient.class); - List result = keyVaultClient.getAliases(); - - assertEquals(0, result.size()); - } + KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null) { + @Override + String httpGet(String uri, Map headers) { + return "fakeValue"; + } + }; + + assertEquals(0, keyVaultClient.getAliases().size()); } @Test public void testGetAliasWithCertificateInfoWith1Page() { - try (MockedStatic utilities = Mockito.mockStatic(HttpUtil.class)) { - utilities.when(() -> HttpUtil.validateUri(anyString(), anyString())).thenCallRealMethod(); - utilities.when(() -> HttpUtil.addTrailingSlashIfRequired(anyString())).thenCallRealMethod(); - - // Create fake certificates. - CertificateItem fakeCertificateItem1 = new CertificateItem(); - fakeCertificateItem1.setId("certificates/fakeCertificateItem1"); + // Create fake certificates. + CertificateItem fakeCertificateItem1 = new CertificateItem(); + fakeCertificateItem1.setId("certificates/fakeCertificateItem1"); - CertificateListResult certificateListResult = new CertificateListResult(); - certificateListResult.setValue(Arrays.asList(fakeCertificateItem1)); + CertificateListResult certificateListResult = new CertificateListResult(); + certificateListResult.setValue(Arrays.asList(fakeCertificateItem1)); - String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); + String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); - utilities.when(() -> HttpUtil.get(notNull(), anyMap())).thenReturn(certificateListResultString); + KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null) { + @Override + String httpGet(String uri, Map headers) { + return certificateListResultString; + } + }; - KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null); - List result = keyVaultClient.getAliases(); - - assertEquals(1, result.size()); - assertTrue(result.contains("fakeCertificateItem1")); - } + List result = keyVaultClient.getAliases(); + assertEquals(1, result.size()); + assertTrue(result.contains("fakeCertificateItem1")); } @Test public void testGetAliasWithCertificateInfoWith2Pages() { - try (MockedStatic utilities = Mockito.mockStatic(HttpUtil.class)) { - utilities.when(() -> HttpUtil.validateUri(anyString(), anyString())).thenCallRealMethod(); - utilities.when(() -> HttpUtil.addTrailingSlashIfRequired(anyString())).thenCallRealMethod(); - - // create fake certificates - CertificateItem fakeCertificateItem1 = new CertificateItem(); - fakeCertificateItem1.setId("certificates/fakeCertificateItem1"); - - CertificateItem fakeCertificateItem2 = new CertificateItem(); - fakeCertificateItem2.setId("certificates/fakeCertificateItem2"); - - CertificateItem fakeCertificateItem3 = new CertificateItem(); - fakeCertificateItem3.setId("certificates/fakeCertificateItem3"); - - // Create first page certificate result. - CertificateListResult certificateListResult = new CertificateListResult(); - certificateListResult.setNextLink("fakeNextLint"); - certificateListResult.setValue(Arrays.asList(fakeCertificateItem1)); - - // Create next page certificate result. - CertificateListResult certificateListResultNext = new CertificateListResult(); - certificateListResultNext.setValue(Arrays.asList(fakeCertificateItem2, fakeCertificateItem3)); - - String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); - String certificateListResultStringNext = JsonConverterUtil.toJson(certificateListResultNext); - - utilities.when(() -> HttpUtil.get(notNull(), anyMap())).thenReturn(certificateListResultString); - utilities.when(() -> HttpUtil.get(eq("fakeNextLint"), anyMap())) - .thenReturn(certificateListResultStringNext); - - KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null); - List result = keyVaultClient.getAliases(); - - assertEquals(3, result.size()); - assertTrue(result - .containsAll(Arrays.asList("fakeCertificateItem1", "fakeCertificateItem2", "fakeCertificateItem3"))); - } + // create fake certificates + CertificateItem fakeCertificateItem1 = new CertificateItem(); + fakeCertificateItem1.setId("certificates/fakeCertificateItem1"); + + CertificateItem fakeCertificateItem2 = new CertificateItem(); + fakeCertificateItem2.setId("certificates/fakeCertificateItem2"); + + CertificateItem fakeCertificateItem3 = new CertificateItem(); + fakeCertificateItem3.setId("certificates/fakeCertificateItem3"); + + // Create first page certificate result. + CertificateListResult certificateListResult = new CertificateListResult(); + certificateListResult.setNextLink("fakeNextLink"); + certificateListResult.setValue(Arrays.asList(fakeCertificateItem1)); + + // Create next page certificate result. + CertificateListResult certificateListResultNext = new CertificateListResult(); + certificateListResultNext.setValue(Arrays.asList(fakeCertificateItem2, fakeCertificateItem3)); + + String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); + String certificateListResultStringNext = JsonConverterUtil.toJson(certificateListResultNext); + + KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null) { + @Override + String httpGet(String uri, Map headers) { + return "fakeNextLink".equals(uri) ? certificateListResultStringNext : certificateListResultString; + } + }; + + List result = keyVaultClient.getAliases(); + assertEquals(3, result.size()); + assertTrue( + result.containsAll(Arrays.asList("fakeCertificateItem1", "fakeCertificateItem2", "fakeCertificateItem3"))); } @Test public void testCacheToken() { - try (MockedStatic tokenUtilMockedStatic = Mockito.mockStatic(AccessTokenUtil.class); - MockedStatic httpUtilMockedStatic = Mockito.mockStatic(HttpUtil.class)) { - - httpUtilMockedStatic.when(() -> HttpUtil.validateUri(anyString(), anyString())).thenCallRealMethod(); - httpUtilMockedStatic.when(() -> HttpUtil.addTrailingSlashIfRequired(anyString())).thenCallRealMethod(); - - AccessToken cacheToken = new AccessToken(); - cacheToken.setExpiresIn(300); // 300 seconds. - - tokenUtilMockedStatic.when(() -> AccessTokenUtil.getAccessToken(anyString(), anyString())) - .thenReturn(cacheToken); - - CertificateItem fakeCertificateItem = new CertificateItem(); - fakeCertificateItem.setId("certificates/fakeCertificateItem"); - - CertificateListResult certificateListResult = new CertificateListResult(); - certificateListResult.setValue(Arrays.asList(fakeCertificateItem)); - - String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); - httpUtilMockedStatic.when(() -> HttpUtil.get(anyString(), anyMap())) - .thenReturn(certificateListResultString); - - KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, ""); - keyVaultClient.getAliases(); - keyVaultClient.getAliases(); // Get aliases the second time. - - tokenUtilMockedStatic.verify(() -> AccessTokenUtil.getAccessToken(anyString(), anyString()), times(1)); - } + AccessToken cacheToken = new AccessToken(); + cacheToken.setExpiresIn(300); // 300 seconds. + + CertificateItem fakeCertificateItem = new CertificateItem(); + fakeCertificateItem.setId("certificates/fakeCertificateItem"); + + CertificateListResult certificateListResult = new CertificateListResult(); + certificateListResult.setValue(Arrays.asList(fakeCertificateItem)); + + String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); + + AtomicInteger getAccessTokenCount = new AtomicInteger(); + KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, "") { + @Override + String httpGet(String uri, Map headers) { + return certificateListResultString; + } + + @Override + AccessToken getAccessToken(String resource, String identity) { + getAccessTokenCount.incrementAndGet(); + return cacheToken; + } + }; + keyVaultClient.getAliases(); + keyVaultClient.getAliases(); // Get aliases the second time. + + assertEquals(1, getAccessTokenCount.get()); } @Test public void testCacheTokenExpired() { - try (MockedStatic tokenUtilMockedStatic = Mockito.mockStatic(AccessTokenUtil.class); - MockedStatic httpUtilMockedStatic = Mockito.mockStatic(HttpUtil.class)) { + AccessToken cacheToken = new AccessToken(); + cacheToken.setExpiresIn(50); // 50 seconds. - httpUtilMockedStatic.when(() -> HttpUtil.validateUri(anyString(), anyString())).thenCallRealMethod(); - httpUtilMockedStatic.when(() -> HttpUtil.addTrailingSlashIfRequired(anyString())).thenCallRealMethod(); + CertificateItem fakeCertificateItem = new CertificateItem(); + fakeCertificateItem.setId("certificates/fakeCertificateItem"); - AccessToken cacheToken = new AccessToken(); - cacheToken.setExpiresIn(50); // 50 seconds. + CertificateListResult certificateListResult = new CertificateListResult(); + certificateListResult.setValue(Arrays.asList(fakeCertificateItem)); - tokenUtilMockedStatic.when(() -> AccessTokenUtil.getAccessToken(anyString(), anyString())) - .thenReturn(cacheToken); + String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); - CertificateItem fakeCertificateItem = new CertificateItem(); - fakeCertificateItem.setId("certificates/fakeCertificateItem"); + AtomicInteger getAccessTokenCount = new AtomicInteger(); + KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, "") { + @Override + String httpGet(String uri, Map headers) { + return certificateListResultString; + } - CertificateListResult certificateListResult = new CertificateListResult(); - certificateListResult.setValue(Arrays.asList(fakeCertificateItem)); + @Override + AccessToken getAccessToken(String resource, String identity) { + getAccessTokenCount.incrementAndGet(); + return cacheToken; + } + }; - String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); - httpUtilMockedStatic.when(() -> HttpUtil.get(anyString(), anyMap())) - .thenReturn(certificateListResultString); + keyVaultClient.getAliases(); + keyVaultClient.getAliases(); // Get aliases the second time. - KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, ""); - keyVaultClient.getAliases(); - keyVaultClient.getAliases(); // Get aliases the second time. - - tokenUtilMockedStatic.verify(() -> AccessTokenUtil.getAccessToken(anyString(), anyString()), times(2)); - } + assertEquals(2, getAccessTokenCount.get()); } @Test public void testAccessTokenAuthentication() { - try (MockedStatic httpUtilMockedStatic = Mockito.mockStatic(HttpUtil.class)) { - httpUtilMockedStatic.when(() -> HttpUtil.validateUri(anyString(), anyString())).thenCallRealMethod(); - httpUtilMockedStatic.when(() -> HttpUtil.addTrailingSlashIfRequired(anyString())).thenCallRealMethod(); + CertificateItem fakeCertificateItem = new CertificateItem(); + fakeCertificateItem.setId("certificates/fakeCertificateItem"); - CertificateItem fakeCertificateItem = new CertificateItem(); - fakeCertificateItem.setId("certificates/fakeCertificateItem"); + CertificateListResult certificateListResult = new CertificateListResult(); + certificateListResult.setValue(Arrays.asList(fakeCertificateItem)); - CertificateListResult certificateListResult = new CertificateListResult(); - certificateListResult.setValue(Arrays.asList(fakeCertificateItem)); + String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); - String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); - httpUtilMockedStatic.when(() -> HttpUtil.get(anyString(), anyMap())) - .thenReturn(certificateListResultString); + // Create client with access token + String testAccessToken = "test-bearer-token-12345"; + KeyVaultClient keyVaultClient + = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null, null, null, null, testAccessToken, false) { + @Override + String httpGet(String uri, Map headers) { + return certificateListResultString; + } + }; - // Create client with access token - String testAccessToken = "test-bearer-token-12345"; - KeyVaultClient keyVaultClient - = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null, null, null, null, testAccessToken, false); + List result = keyVaultClient.getAliases(); - List result = keyVaultClient.getAliases(); - - // Verify that the access token was used - assertEquals(1, result.size()); - assertTrue(result.contains("fakeCertificateItem")); - } + // Verify that the access token was used + assertEquals(1, result.size()); + assertTrue(result.contains("fakeCertificateItem")); } @Test public void testAuthenticationPriority() { - try (MockedStatic httpUtilMockedStatic = Mockito.mockStatic(HttpUtil.class); - MockedStatic tokenUtilMockedStatic = Mockito.mockStatic(AccessTokenUtil.class)) { - - httpUtilMockedStatic.when(() -> HttpUtil.validateUri(anyString(), anyString())).thenCallRealMethod(); - httpUtilMockedStatic.when(() -> HttpUtil.addTrailingSlashIfRequired(anyString())).thenCallRealMethod(); - - AccessToken accessToken = new AccessToken("fake-token", 3600); - tokenUtilMockedStatic.when(() -> AccessTokenUtil.getAccessToken(anyString(), anyString())) - .thenReturn(accessToken); - - CertificateItem fakeCertificateItem = new CertificateItem(); - fakeCertificateItem.setId("certificates/fakeCertificateItem"); - - CertificateListResult certificateListResult = new CertificateListResult(); - certificateListResult.setValue(Arrays.asList(fakeCertificateItem)); - - String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); - httpUtilMockedStatic.when(() -> HttpUtil.get(anyString(), anyMap())) - .thenReturn(certificateListResultString); - - // Test 1: Managed Identity should take priority over access token - KeyVaultClient client1 - = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null, null, null, "managed-id", "bearer-token", false); - client1.getAliases(); - tokenUtilMockedStatic.verify(() -> AccessTokenUtil.getAccessToken(anyString(), eq("managed-id")), times(1)); - - // Test 2: Access token should be used when managed identity is not set - KeyVaultClient client2 - = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null, null, null, null, "bearer-token", false); - List result = client2.getAliases(); - assertEquals(1, result.size()); - assertTrue(result.contains("fakeCertificateItem")); - } + AtomicInteger getAccessTokenCount = new AtomicInteger(); + AccessToken accessToken = new AccessToken("fake-token", 3600); + + CertificateItem fakeCertificateItem = new CertificateItem(); + fakeCertificateItem.setId("certificates/fakeCertificateItem"); + + CertificateListResult certificateListResult = new CertificateListResult(); + certificateListResult.setValue(Arrays.asList(fakeCertificateItem)); + + String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); + + // Test 1: Managed Identity should take priority over access token + KeyVaultClient client1 + = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null, null, null, "managed-id", "bearer-token", false) { + @Override + String httpGet(String uri, Map headers) { + return certificateListResultString; + } + + @Override + AccessToken getAccessToken(String resource, String identity) { + if ("managed-id".equals(identity)) { + getAccessTokenCount.incrementAndGet(); + } + return accessToken; + } + }; + client1.getAliases(); + + // Test 2: Access token should be used when managed identity is not set + KeyVaultClient client2 + = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null, null, null, null, "bearer-token", false) { + @Override + String httpGet(String uri, Map headers) { + return certificateListResultString; + } + + @Override + AccessToken getAccessToken(String resource, String identity) { + if ("managed-id".equals(identity)) { + getAccessTokenCount.incrementAndGet(); + } + return accessToken; + } + }; + + List result = client2.getAliases(); + assertEquals(1, result.size()); + assertTrue(result.contains("fakeCertificateItem")); + + assertEquals(1, getAccessTokenCount.get()); } @EnabledIfEnvironmentVariable(named = "AZURE_KEYVAULT_CERTIFICATE_NAME", matches = "myalias") diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/MockKeyVaultClient.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/MockKeyVaultClient.java index 94834e2f2ed2..5d3d656297e9 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/MockKeyVaultClient.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/MockKeyVaultClient.java @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.security.keyvault.jca.implementation.mocking; - -import com.azure.security.keyvault.jca.implementation.KeyVaultClient; +package com.azure.security.keyvault.jca.implementation; public class MockKeyVaultClient extends KeyVaultClient { public MockKeyVaultClient() { diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java index 7e41fa8a92b9..3756c8646fe2 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java @@ -6,7 +6,7 @@ import com.azure.security.keyvault.jca.implementation.KeyVaultClient; import com.azure.security.keyvault.jca.implementation.mocking.MockCertificate; import com.azure.security.keyvault.jca.implementation.mocking.MockKey; -import com.azure.security.keyvault.jca.implementation.mocking.MockKeyVaultClient; +import com.azure.security.keyvault.jca.implementation.MockKeyVaultClient; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSignatureTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSignatureTest.java index 5f0685815cd9..798dbb25d332 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSignatureTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessEcSignatureTest.java @@ -6,7 +6,7 @@ import com.azure.security.keyvault.jca.KeyVaultEncode; import com.azure.security.keyvault.jca.implementation.KeyVaultClient; import com.azure.security.keyvault.jca.implementation.KeyVaultPrivateKey; -import com.azure.security.keyvault.jca.implementation.mocking.MockKeyVaultClient; +import com.azure.security.keyvault.jca.implementation.MockKeyVaultClient; import com.azure.security.keyvault.jca.implementation.mocking.MockPrivateKey; import com.azure.security.keyvault.jca.implementation.mocking.MockPublicKey; import org.junit.jupiter.api.Assertions; diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignatureTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignatureTest.java index 946f3e35b843..08ad83fb48ac 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignatureTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeylessRsaSsaPssSignatureTest.java @@ -5,7 +5,7 @@ import com.azure.security.keyvault.jca.implementation.KeyVaultClient; import com.azure.security.keyvault.jca.implementation.KeyVaultPrivateKey; -import com.azure.security.keyvault.jca.implementation.mocking.MockKeyVaultClient; +import com.azure.security.keyvault.jca.implementation.MockKeyVaultClient; import com.azure.security.keyvault.jca.implementation.mocking.MockPrivateKey; import com.azure.security.keyvault.jca.implementation.mocking.MockPublicKey; import org.junit.jupiter.api.BeforeEach; From 19ff957402ef16e9ed5f71c2ff1499643ce9cf58 Mon Sep 17 00:00:00 2001 From: alzimmermsft <48699787+alzimmermsft@users.noreply.github.com> Date: Wed, 5 Aug 2026 10:30:44 -0400 Subject: [PATCH 5/7] Merge in main and resolve merge conflict --- .../eventhubs/stress/scenarios/EventForwarder.java | 3 +-- .../messaging/eventhubs/stress/util/TelemetryHelper.java | 2 +- sdk/keyvault/azure-security-keyvault-jca/pom.xml | 1 - .../keyvault/jca/implementation/KeyVaultClient.java | 6 +++--- .../keyvault/jca/implementation/utils/AccessTokenUtil.java | 3 +-- 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/sdk/eventhubs/azure-messaging-eventhubs-stress/src/main/java/com/azure/messaging/eventhubs/stress/scenarios/EventForwarder.java b/sdk/eventhubs/azure-messaging-eventhubs-stress/src/main/java/com/azure/messaging/eventhubs/stress/scenarios/EventForwarder.java index 4fd67886541d..907ecf0f6873 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs-stress/src/main/java/com/azure/messaging/eventhubs/stress/scenarios/EventForwarder.java +++ b/sdk/eventhubs/azure-messaging-eventhubs-stress/src/main/java/com/azure/messaging/eventhubs/stress/scenarios/EventForwarder.java @@ -105,8 +105,7 @@ public void run() { private EventHubProducerAsyncClient getForwardProducer() { final TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build(); final EventHubClientBuilder builder = new EventHubClientBuilder() - .credential(options.getEventHubsFullyQualifiedNamespace(), forwardEventHubName, - tokenCredential) + .credential(options.getEventHubsFullyQualifiedNamespace(), forwardEventHubName, tokenCredential) .retryOptions(new AmqpRetryOptions().setTryTimeout(Duration.ofSeconds(10))) .transportType(options.getAmqpTransportType()) .consumerGroup(options.getEventHubsConsumerGroup()); diff --git a/sdk/eventhubs/azure-messaging-eventhubs-stress/src/main/java/com/azure/messaging/eventhubs/stress/util/TelemetryHelper.java b/sdk/eventhubs/azure-messaging-eventhubs-stress/src/main/java/com/azure/messaging/eventhubs/stress/util/TelemetryHelper.java index 393155d8914e..0f9f6a37a768 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs-stress/src/main/java/com/azure/messaging/eventhubs/stress/util/TelemetryHelper.java +++ b/sdk/eventhubs/azure-messaging-eventhubs-stress/src/main/java/com/azure/messaging/eventhubs/stress/util/TelemetryHelper.java @@ -90,7 +90,7 @@ public TelemetryHelper(Class scenarioClass) { */ private static OpenTelemetry init() { System.setProperty("otel.java.global-autoconfigure.enabled", "true"); - + AutoConfiguredOpenTelemetrySdkBuilder sdkBuilder = AutoConfiguredOpenTelemetrySdk.builder(); String applicationInsightsConnectionString = System.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING"); if (applicationInsightsConnectionString == null) { diff --git a/sdk/keyvault/azure-security-keyvault-jca/pom.xml b/sdk/keyvault/azure-security-keyvault-jca/pom.xml index b68124cc33ee..c970a22bd4ae 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/pom.xml +++ b/sdk/keyvault/azure-security-keyvault-jca/pom.xml @@ -1,5 +1,4 @@ - diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java index fe1fe0d1106e..7a529b965917 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java @@ -512,7 +512,7 @@ public byte[] getSignedWithPrivateKey(String digestName, String digestValue, Str String bodyString = "{\"alg\": \"" + digestName + "\", \"value\": \"" + digestValue + "\"}"; Map headers = Collections.singletonMap("Authorization", "Bearer " + getAccessToken()); - String response = httpPost("/sign" + API_VERSION_POSTFIX, headers, bodyString, "application/json"); + String response = httpPost(headers, bodyString); if (response != null) { try { @@ -591,8 +591,8 @@ String httpGet(String uri, Map headers) { return HttpUtil.get(uri, headers); } - String httpPost(String uri, Map headers, String body, String contentType) { - return HttpUtil.post(uri, headers, body, contentType); + String httpPost(Map headers, String body) { + return HttpUtil.post("/sign?api-version=7.1", headers, body, "application/json"); } AccessToken getAccessToken(String resource, String identity) { diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/AccessTokenUtil.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/AccessTokenUtil.java index 2be57d9e457b..9534bff23dd2 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/AccessTokenUtil.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/AccessTokenUtil.java @@ -188,7 +188,6 @@ public static boolean isWorkloadIdentityAvailable(String clientId, String tenant * @param resource The resource scope (will be appended with /.default if not already present). * @param tenantId Tenant ID to use. If blank, fallback to environment variable AZURE_TENANT_ID. * @param clientId Client ID of the managed identity to use. If blank, fallback to environment variable AZURE_CLIENT_ID. - * @param tokenFilePath Path to the federated token file. If blank, fallback to environment variable AZURE_FEDERATED_TOKEN_FILE. * @return An access token, or null if the operation fails. */ public static AccessToken getAccessTokenWithWorkloadIdentity(String resource, String tenantId, String clientId) { @@ -219,7 +218,7 @@ public static AccessToken getAccessTokenWithWorkloadIdentity(String resource, St String requestUrl = buildTokenRequestUrl(authorityHost, effectiveTenantId); String requestBody = buildTokenRequestBody(effectiveClientId, federatedToken, scope); - String response = HttpUtil.post(requestUrl, requestBody, "application/x-www-form-urlencoded"); + String response = HttpUtil.post(requestUrl, null, requestBody, "application/x-www-form-urlencoded"); AccessToken result = parseAccessTokenResponse(response); LOGGER.exiting("AccessTokenUtil", "getAccessTokenWithWorkloadIdentity", result); From 2feddfbe51e7d67523aa117f818c8150bebe4e99 Mon Sep 17 00:00:00 2001 From: Victor Colin Amador Date: Fri, 7 Aug 2026 18:37:56 -0700 Subject: [PATCH 6/7] Removed Mockito and related dependencies from POM --- .../azure-security-keyvault-jca/pom.xml | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/sdk/keyvault/azure-security-keyvault-jca/pom.xml b/sdk/keyvault/azure-security-keyvault-jca/pom.xml index c970a22bd4ae..074c49f4ce83 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/pom.xml +++ b/sdk/keyvault/azure-security-keyvault-jca/pom.xml @@ -55,34 +55,6 @@ 1.7.36 - - - org.mockito - mockito-inline - 4.11.0 - test - - - - - net.bytebuddy - byte-buddy - 1.17.7 - test - - - net.bytebuddy - byte-buddy-agent - 1.17.7 - test - - - - com.github.spotbugs - spotbugs-annotations - 4.8.3 - test - com.azure azure-core From 33caba1f72b700fb3fb4f16a81eb9a036ec388f2 Mon Sep 17 00:00:00 2001 From: Victor Colin Amador Date: Fri, 7 Aug 2026 19:03:58 -0700 Subject: [PATCH 7/7] Fixed compilation issue --- .../implementation/KeyVaultClientTest.java | 144 +++++++++--------- 1 file changed, 70 insertions(+), 74 deletions(-) diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/KeyVaultClientTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/KeyVaultClientTest.java index b303f7b21632..0c6090159979 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/KeyVaultClientTest.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/KeyVaultClientTest.java @@ -99,93 +99,89 @@ String httpGet(String uri, Map headers) { @Test public void testGetAliasFiltersOutDisabledCertificate() { - try (MockedStatic utilities = Mockito.mockStatic(HttpUtil.class)) { - utilities.when(() -> HttpUtil.validateUri(anyString(), anyString())).thenCallRealMethod(); - utilities.when(() -> HttpUtil.addTrailingSlashIfRequired(anyString())).thenCallRealMethod(); - - // Enabled certificate. - CertificateItemAttributes enabledAttributes = new CertificateItemAttributes(); - enabledAttributes.setEnabled(true); - CertificateItem enabledCertificate = new CertificateItem(); - enabledCertificate.setId("certificates/client-cert-active"); - enabledCertificate.setAttributes(enabledAttributes); - - // Disabled certificate. This one previously caused an HTTP 403 while initializing the keystore. - CertificateItemAttributes disabledAttributes = new CertificateItemAttributes(); - disabledAttributes.setEnabled(false); - CertificateItem disabledCertificate = new CertificateItem(); - disabledCertificate.setId("certificates/client-cert-unused"); - disabledCertificate.setAttributes(disabledAttributes); - - CertificateListResult certificateListResult = new CertificateListResult(); - certificateListResult.setValue(Arrays.asList(enabledCertificate, disabledCertificate)); - - String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); - utilities.when(() -> HttpUtil.get(notNull(), anyMap())).thenReturn(certificateListResultString); - - KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null); - List result = keyVaultClient.getAliases(); - - assertEquals(1, result.size()); - assertTrue(result.contains("client-cert-active")); - assertFalse(result.contains("client-cert-unused")); - } + // Enabled certificate. + CertificateItemAttributes enabledAttributes = new CertificateItemAttributes(); + enabledAttributes.setEnabled(true); + CertificateItem enabledCertificate = new CertificateItem(); + enabledCertificate.setId("certificates/client-cert-active"); + enabledCertificate.setAttributes(enabledAttributes); + + // Disabled certificate. This one previously caused an HTTP 403 while initializing the keystore. + CertificateItemAttributes disabledAttributes = new CertificateItemAttributes(); + disabledAttributes.setEnabled(false); + CertificateItem disabledCertificate = new CertificateItem(); + disabledCertificate.setId("certificates/client-cert-unused"); + disabledCertificate.setAttributes(disabledAttributes); + + CertificateListResult certificateListResult = new CertificateListResult(); + certificateListResult.setValue(Arrays.asList(enabledCertificate, disabledCertificate)); + + String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); + + KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null) { + @Override + String httpGet(String uri, Map headers) { + return certificateListResultString; + } + }; + List result = keyVaultClient.getAliases(); + + assertEquals(1, result.size()); + assertTrue(result.contains("client-cert-active")); + assertFalse(result.contains("client-cert-unused")); } @Test public void testGetAliasKeepsEnabledAndAttributelessCertificates() { - try (MockedStatic utilities = Mockito.mockStatic(HttpUtil.class)) { - utilities.when(() -> HttpUtil.validateUri(anyString(), anyString())).thenCallRealMethod(); - utilities.when(() -> HttpUtil.addTrailingSlashIfRequired(anyString())).thenCallRealMethod(); - - // Certificate explicitly enabled. - CertificateItemAttributes enabledAttributes = new CertificateItemAttributes(); - enabledAttributes.setEnabled(true); - CertificateItem enabledCertificate = new CertificateItem(); - enabledCertificate.setId("certificates/enabledCertificate"); - enabledCertificate.setAttributes(enabledAttributes); + // Certificate explicitly enabled. + CertificateItemAttributes enabledAttributes = new CertificateItemAttributes(); + enabledAttributes.setEnabled(true); + CertificateItem enabledCertificate = new CertificateItem(); + enabledCertificate.setId("certificates/enabledCertificate"); + enabledCertificate.setAttributes(enabledAttributes); - // Certificate without attributes, which must be treated as enabled for backward compatibility. - CertificateItem attributelessCertificate = new CertificateItem(); - attributelessCertificate.setId("certificates/attributelessCertificate"); + // Certificate without attributes, which must be treated as enabled for backward compatibility. + CertificateItem attributelessCertificate = new CertificateItem(); + attributelessCertificate.setId("certificates/attributelessCertificate"); - CertificateListResult certificateListResult = new CertificateListResult(); - certificateListResult.setValue(Arrays.asList(enabledCertificate, attributelessCertificate)); + CertificateListResult certificateListResult = new CertificateListResult(); + certificateListResult.setValue(Arrays.asList(enabledCertificate, attributelessCertificate)); - String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); - utilities.when(() -> HttpUtil.get(notNull(), anyMap())).thenReturn(certificateListResultString); + String certificateListResultString = JsonConverterUtil.toJson(certificateListResult); - KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null); - List result = keyVaultClient.getAliases(); + KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null) { + @Override + String httpGet(String uri, Map headers) { + return certificateListResultString; + } + }; + List result = keyVaultClient.getAliases(); - assertEquals(2, result.size()); - assertTrue(result.containsAll(Arrays.asList("enabledCertificate", "attributelessCertificate"))); - } + assertEquals(2, result.size()); + assertTrue(result.containsAll(Arrays.asList("enabledCertificate", "attributelessCertificate"))); } @Test public void testGetAliasFiltersDisabledCertificateFromRawResponse() { - try (MockedStatic utilities = Mockito.mockStatic(HttpUtil.class)) { - utilities.when(() -> HttpUtil.validateUri(anyString(), anyString())).thenCallRealMethod(); - utilities.when(() -> HttpUtil.addTrailingSlashIfRequired(anyString())).thenCallRealMethod(); - - // A response that mirrors the shape returned by the Azure Key Vault "list certificates" REST API, with one - // enabled and one disabled certificate. - String rawResponse = "{\"value\":[" - + "{\"id\":\"https://fake.vault.azure.net/certificates/client-cert-active\"," - + "\"attributes\":{\"enabled\":true,\"nbf\":1783324860,\"exp\":1814861460}}," - + "{\"id\":\"https://fake.vault.azure.net/certificates/client-cert-unused\"," - + "\"attributes\":{\"enabled\":false,\"nbf\":1783324860,\"exp\":1814861460}}]," + "\"nextLink\":null}"; - - utilities.when(() -> HttpUtil.get(notNull(), anyMap())).thenReturn(rawResponse); - - KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null); - List result = keyVaultClient.getAliases(); - - assertEquals(1, result.size()); - assertTrue(result.contains("client-cert-active")); - assertFalse(result.contains("client-cert-unused")); - } + // A response that mirrors the shape returned by the Azure Key Vault "list certificates" REST API, with one + // enabled and one disabled certificate. + String rawResponse = "{\"value\":[" + + "{\"id\":\"https://fake.vault.azure.net/certificates/client-cert-active\"," + + "\"attributes\":{\"enabled\":true,\"nbf\":1783324860,\"exp\":1814861460}}," + + "{\"id\":\"https://fake.vault.azure.net/certificates/client-cert-unused\"," + + "\"attributes\":{\"enabled\":false,\"nbf\":1783324860,\"exp\":1814861460}}]," + "\"nextLink\":null}"; + + KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null) { + @Override + String httpGet(String uri, Map headers) { + return rawResponse; + } + }; + List result = keyVaultClient.getAliases(); + + assertEquals(1, result.size()); + assertTrue(result.contains("client-cert-active")); + assertFalse(result.contains("client-cert-unused")); } @Test