diff --git a/sdk/keyvault/azure-security-keyvault-jca/CHANGELOG.md b/sdk/keyvault/azure-security-keyvault-jca/CHANGELOG.md index c406c10f73fb..57ba0c7bd1dd 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/CHANGELOG.md +++ b/sdk/keyvault/azure-security-keyvault-jca/CHANGELOG.md @@ -3,6 +3,7 @@ ## 2.11.0-beta.1 (Unreleased) ### Features Added +- Added support for bearer token authentication via the `azure.keyvault.access-token` system property. This allows users to provide a pre-obtained access token for authentication, enabling multi-factor authentication scenarios without requiring client ID and client secret. Authentication priority order is: Managed Identity > Access Token > Client Credentials. ### Breaking Changes diff --git a/sdk/keyvault/azure-security-keyvault-jca/README.md b/sdk/keyvault/azure-security-keyvault-jca/README.md index b9dfaa71856c..90dbff7311f1 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/README.md +++ b/sdk/keyvault/azure-security-keyvault-jca/README.md @@ -84,6 +84,7 @@ The JCA library supports configuring the following options: * `azure.keyvault.client-id`: The client/application ID used for authentication. * `azure.keyvault.client-secret`: The client secret for authentication when using client credentials. * `azure.keyvault.managed-identity`: Indicates whether Managed Identity authentication is enabled. +* `azure.keyvault.access-token`: The access token for authentication. This allows using a pre-obtained bearer token instead of client credentials. * `azure.cert-path.well-known`: The path where the well-known certificate is stored. * `azure.cert-path.custom`: The path where the custom certificate is stored. * `azure.keyvault.jca.refresh-certificates-when-have-un-trust-certificate`: Indicates whether to refresh certificates when have untrusted certificate. diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultKeyStore.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultKeyStore.java index 4a9fd191562a..ee2d5c23cf7c 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultKeyStore.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultKeyStore.java @@ -127,6 +127,7 @@ public KeyVaultKeyStore() { String clientId = System.getProperty("azure.keyvault.client-id"); String clientSecret = System.getProperty("azure.keyvault.client-secret"); String managedIdentity = System.getProperty("azure.keyvault.managed-identity"); + String accessToken = System.getProperty("azure.keyvault.access-token"); boolean disableChallengeResourceVerification = Boolean.parseBoolean(System.getProperty("azure.keyvault.disable-challenge-resource-verification")); long refreshInterval = getRefreshInterval(); @@ -146,7 +147,7 @@ public KeyVaultKeyStore() { LOGGER.log(FINE, String.format("Loaded custom certificates: %s.", customCertificates.getAliases())); keyVaultCertificates = new KeyVaultCertificates(refreshInterval, keyVaultUri, tenantId, clientId, clientSecret, - managedIdentity, disableChallengeResourceVerification); + managedIdentity, accessToken, disableChallengeResourceVerification); LOGGER.log(FINE, String.format("Loaded Key Vault certificates: %s.", keyVaultCertificates.getAliases())); classpathCertificates = new ClasspathCertificates(); @@ -184,7 +185,7 @@ public static KeyStore getKeyVaultKeyStoreBySystemProperty() KeyVaultLoadStoreParameter keyVaultLoadStoreParameter = new KeyVaultLoadStoreParameter( System.getProperty("azure.keyvault.uri"), System.getProperty("azure.keyvault.tenant-id"), System.getProperty("azure.keyvault.client-id"), System.getProperty("azure.keyvault.client-secret"), - System.getProperty("azure.keyvault.managed-identity")); + System.getProperty("azure.keyvault.managed-identity"), System.getProperty("azure.keyvault.access-token")); if (Boolean.parseBoolean(System.getProperty("azure.keyvault.disable-challenge-resource-verification"))) { keyVaultLoadStoreParameter.disableChallengeResourceVerification(); @@ -399,7 +400,7 @@ public void engineLoad(KeyStore.LoadStoreParameter param) { keyVaultCertificates.updateKeyVaultClient(parameter.getUri(), parameter.getTenantId(), parameter.getClientId(), parameter.getClientSecret(), parameter.getManagedIdentity(), - parameter.isChallengeResourceVerificationDisabled()); + parameter.getAccessToken(), parameter.isChallengeResourceVerificationDisabled()); } classpathCertificates.loadCertificatesFromClasspath(); diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultLoadStoreParameter.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultLoadStoreParameter.java index 5a7f8dbe9762..1b75896e2a22 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultLoadStoreParameter.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultLoadStoreParameter.java @@ -36,6 +36,11 @@ public final class KeyVaultLoadStoreParameter implements KeyStore.LoadStoreParam */ private final String managedIdentity; + /** + * Stores the access token. + */ + private final String accessToken; + /** * Stores a flag indicating if challenge resource verification shall be disabled. */ @@ -47,7 +52,7 @@ public final class KeyVaultLoadStoreParameter implements KeyStore.LoadStoreParam * @param keyVaultUri The Azure Key Vault URI. */ public KeyVaultLoadStoreParameter(String keyVaultUri) { - this(keyVaultUri, null, null, null, null); + this(keyVaultUri, null, null, null, null, null); } /** @@ -57,7 +62,7 @@ public KeyVaultLoadStoreParameter(String keyVaultUri) { * @param managedIdentity The managed identity. */ public KeyVaultLoadStoreParameter(String keyVaultUri, String managedIdentity) { - this(keyVaultUri, null, null, null, managedIdentity); + this(keyVaultUri, null, null, null, managedIdentity, null); } /** @@ -69,7 +74,7 @@ public KeyVaultLoadStoreParameter(String keyVaultUri, String managedIdentity) { * @param clientSecret The client secret. */ public KeyVaultLoadStoreParameter(String keyVaultUri, String tenantId, String clientId, String clientSecret) { - this(keyVaultUri, tenantId, clientId, clientSecret, null); + this(keyVaultUri, tenantId, clientId, clientSecret, null, null); } /** @@ -83,12 +88,28 @@ public KeyVaultLoadStoreParameter(String keyVaultUri, String tenantId, String cl */ public KeyVaultLoadStoreParameter(String keyVaultUri, String tenantId, String clientId, String clientSecret, String managedIdentity) { + this(keyVaultUri, tenantId, clientId, clientSecret, managedIdentity, null); + } + + /** + * Constructor. + * + * @param keyVaultUri The Azure Key Vault URI. + * @param tenantId The tenant id. + * @param clientId The client id. + * @param clientSecret The client secret. + * @param managedIdentity The managed identity. + * @param accessToken The access token. + */ + public KeyVaultLoadStoreParameter(String keyVaultUri, String tenantId, String clientId, String clientSecret, + String managedIdentity, String accessToken) { this.keyVaultUri = keyVaultUri; this.tenantId = tenantId; this.clientId = clientId; this.clientSecret = clientSecret; this.managedIdentity = managedIdentity; + this.accessToken = accessToken; } /** @@ -128,6 +149,15 @@ public String getManagedIdentity() { return managedIdentity; } + /** + * Get the access token. + * + * @return The access token. + */ + public String getAccessToken() { + return accessToken; + } + /** * Get the tenant id. * 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 af460d746385..045c69c52b68 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 @@ -89,6 +89,11 @@ public class KeyVaultClient { */ private String managedIdentity; + /** + * Stores the provided access token string. + */ + private final String providedAccessToken; + /** * Stores the token. */ @@ -106,7 +111,7 @@ public class KeyVaultClient { * @param managedIdentity The user-assigned managed identity object ID. */ KeyVaultClient(String keyVaultUri, String managedIdentity) { - this(keyVaultUri, null, null, null, managedIdentity, false); + this(keyVaultUri, null, null, null, managedIdentity, null, false); } /** @@ -118,7 +123,7 @@ public class KeyVaultClient { * @param clientSecret The client secret. */ public KeyVaultClient(String keyVaultUri, String tenantId, String clientId, String clientSecret) { - this(keyVaultUri, tenantId, clientId, clientSecret, null, false); + this(keyVaultUri, tenantId, clientId, clientSecret, null, null, false); } /** @@ -133,6 +138,23 @@ public KeyVaultClient(String keyVaultUri, String tenantId, String clientId, Stri */ public KeyVaultClient(String keyVaultUri, String tenantId, String clientId, String clientSecret, String managedIdentity, boolean disableChallengeResourceVerification) { + this(keyVaultUri, tenantId, clientId, clientSecret, managedIdentity, null, + disableChallengeResourceVerification); + } + + /** + * Constructor. + * + * @param keyVaultUri The Azure Key Vault URI. + * @param tenantId The tenant ID. + * @param clientId The client ID. + * @param clientSecret The client secret. + * @param managedIdentity The user-assigned managed identity object ID. + * @param providedAccessToken The access token for authentication. + * @param disableChallengeResourceVerification Indicates if the challenge resource verification should be disabled. + */ + public KeyVaultClient(String keyVaultUri, String tenantId, String clientId, String clientSecret, + String managedIdentity, String providedAccessToken, boolean disableChallengeResourceVerification) { LOGGER.log(INFO, "Using Azure Key Vault: {0}", keyVaultUri); @@ -147,6 +169,7 @@ public KeyVaultClient(String keyVaultUri, String tenantId, String clientId, Stri this.clientId = clientId; this.clientSecret = clientSecret; this.managedIdentity = managedIdentity; + this.providedAccessToken = providedAccessToken; this.disableChallengeResourceVerification = disableChallengeResourceVerification; } @@ -156,10 +179,11 @@ public static KeyVaultClient createKeyVaultClientBySystemProperty() { String clientId = System.getProperty("azure.keyvault.client-id"); String clientSecret = System.getProperty("azure.keyvault.client-secret"); String managedIdentity = System.getProperty("azure.keyvault.managed-identity"); + String accessToken = System.getProperty("azure.keyvault.access-token"); boolean disableChallengeResourceVerification = Boolean.parseBoolean(System.getProperty("azure.keyvault.disable-challenge-resource-verification")); - return new KeyVaultClient(keyVaultUri, tenantId, clientId, clientSecret, managedIdentity, + return new KeyVaultClient(keyVaultUri, tenantId, clientId, clientSecret, managedIdentity, accessToken, disableChallengeResourceVerification); } @@ -173,7 +197,7 @@ private String getAccessToken() { return accessToken.getAccessToken(); } - accessToken = getAccessTokenByHttpRequest(); + accessToken = obtainAccessToken(); if (accessToken == null) { LOGGER.log(WARNING, "Access token not returned."); return null; @@ -183,14 +207,14 @@ private String getAccessToken() { } /** - * Get the access token. + * Obtain the access token. * * @return The access token. */ - private AccessToken getAccessTokenByHttpRequest() { - LOGGER.entering("KeyVaultClient", "getAccessTokenByHttpRequest"); + private AccessToken obtainAccessToken() { + LOGGER.entering("KeyVaultClient", "obtainAccessToken"); - AccessToken accessToken = null; + AccessToken result = null; try { String resource = URLEncoder.encode(keyVaultBaseUri, "UTF-8"); @@ -199,21 +223,31 @@ private AccessToken getAccessTokenByHttpRequest() { managedIdentity = URLEncoder.encode(managedIdentity, "UTF-8"); } - if (tenantId != null && clientId != null && clientSecret != null) { + // 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); + } else if (providedAccessToken != null && !providedAccessToken.isEmpty()) { + LOGGER.info("Using provided access token for authentication"); + // Create an AccessToken object from the provided token string + // Set expiration to a very large value since we cannot refresh provided tokens. + // When the token actually expires, Azure will return authentication errors, + // which will inform the user to provide a new token. + result = new AccessToken(providedAccessToken, Long.MAX_VALUE / 1000); + } else if (tenantId != null && clientId != null && clientSecret != null) { + LOGGER.info("Using client credentials (client ID/secret) for authentication"); String aadAuthenticationUri = getLoginUri(keyVaultUri + "certificates" + API_VERSION_POSTFIX, disableChallengeResourceVerification); - accessToken + result = AccessTokenUtil.getAccessToken(resource, aadAuthenticationUri, tenantId, clientId, clientSecret); - } else { - accessToken = AccessTokenUtil.getAccessToken(resource, managedIdentity); } } catch (UnsupportedEncodingException e) { LOGGER.log(WARNING, "Could not obtain access token to authenticate with.", e); } - LOGGER.exiting("KeyVaultClient", "getAccessTokenByHttpRequest", accessToken); + LOGGER.exiting("KeyVaultClient", "obtainAccessToken", result); - return accessToken; + return result; } /** diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificates.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificates.java index f9075d6eebe1..f4636abb2e0b 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificates.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificates.java @@ -50,11 +50,11 @@ public final class KeyVaultCertificates implements AzureCertificates { private final long refreshInterval; public KeyVaultCertificates(long refreshInterval, String keyVaultUri, String tenantId, String clientId, - String clientSecret, String managedIdentity, boolean disableChallengeResourceVerification) { + String clientSecret, String managedIdentity, String accessToken, boolean disableChallengeResourceVerification) { this.refreshInterval = refreshInterval; - updateKeyVaultClient(keyVaultUri, tenantId, clientId, clientSecret, managedIdentity, + updateKeyVaultClient(keyVaultUri, tenantId, clientId, clientSecret, managedIdentity, accessToken, disableChallengeResourceVerification); } @@ -71,14 +71,15 @@ public KeyVaultCertificates(long refreshInterval, KeyVaultClient keyVaultClient) * @param clientId Client ID. * @param clientSecret Client secret. * @param managedIdentity Managed identity. + * @param accessToken Access token. * @param disableChallengeResourceVerification Indicates if the challenge resource verification should be disabled. */ public void updateKeyVaultClient(String keyVaultUri, String tenantId, String clientId, String clientSecret, - String managedIdentity, boolean disableChallengeResourceVerification) { + String managedIdentity, String accessToken, boolean disableChallengeResourceVerification) { if (keyVaultUri != null) { keyVaultClient = new KeyVaultClient(keyVaultUri, tenantId, clientId, clientSecret, managedIdentity, - disableChallengeResourceVerification); + accessToken, disableChallengeResourceVerification); } else { keyVaultClient = null; } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/model/AccessToken.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/model/AccessToken.java index 5fdd65669d98..f05676679bd0 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/model/AccessToken.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/model/AccessToken.java @@ -24,6 +24,23 @@ public class AccessToken implements JsonSerializable { */ private long expiresIn; + /** + * Default constructor. + */ + public AccessToken() { + } + + /** + * Constructor with access token and expiration. + * + * @param accessToken The access token. + * @param expiresIn The life duration of the access token in seconds. + */ + public AccessToken(String accessToken, long expiresIn) { + this.accessToken = accessToken; + this.expiresIn = expiresIn; + } + /** * Get the life duration of the access token in seconds. * diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultClientTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultClientTest.java deleted file mode 100644 index 81f927739527..000000000000 --- a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultClientTest.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.security.keyvault.jca; - -import com.azure.security.keyvault.jca.implementation.KeyVaultClient; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; - -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 KeyVaultClientTest { - private static KeyVaultClient keyVaultClient; - private static String certificateName; - - @BeforeAll - public static void setEnvironmentProperty() { - keyVaultClient = new KeyVaultClient(PropertyConvertorUtils.getPropertyValue("AZURE_KEYVAULT_ENDPOINT"), - PropertyConvertorUtils.getPropertyValue("AZURE_KEYVAULT_TENANT_ID"), - PropertyConvertorUtils.getPropertyValue("AZURE_KEYVAULT_CLIENT_ID"), - PropertyConvertorUtils.getPropertyValue("AZURE_KEYVAULT_CLIENT_SECRET")); - certificateName = PropertyConvertorUtils.getPropertyValue("AZURE_KEYVAULT_CERTIFICATE_NAME"); - } - - @Test - public void testGetAliases() { - assertTrue(keyVaultClient.getAliases().contains(certificateName)); - } - - @Test - public void testGetCertificate() { - assertNotNull(keyVaultClient.getCertificate(certificateName)); - } - - @Test - public void testGetCertificateChain() { - assertNotNull(keyVaultClient.getCertificateChain(certificateName)); - } - - @Test - public void testGetKey() { - assertNotNull(keyVaultClient.getKey(certificateName, null)); - } -} 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 a294686b164f..2bc9d7ea174a 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 @@ -3,24 +3,23 @@ package com.azure.security.keyvault.jca.implementation; +import com.azure.security.keyvault.jca.PropertyConvertorUtils; 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.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.mockito.MockedStatic; import org.mockito.Mockito; -import java.security.cert.Certificate; import java.util.Arrays; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; @@ -40,7 +39,7 @@ public void testGetAliasWithCertificateInfoWith0Page() { KeyVaultClient keyVaultClient = mock(KeyVaultClient.class); List result = keyVaultClient.getAliases(); - assertEquals(result.size(), 0); + assertEquals(0, result.size()); } } @@ -64,7 +63,7 @@ public void testGetAliasWithCertificateInfoWith1Page() { KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null); List result = keyVaultClient.getAliases(); - assertEquals(result.size(), 1); + assertEquals(1, result.size()); assertTrue(result.contains("fakeCertificateItem1")); } } @@ -104,44 +103,12 @@ public void testGetAliasWithCertificateInfoWith2Pages() { KeyVaultClient keyVaultClient = new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null); List result = keyVaultClient.getAliases(); - assertEquals(result.size(), 3); + assertEquals(3, result.size()); assertTrue(result .containsAll(Arrays.asList("fakeCertificateItem1", "fakeCertificateItem2", "fakeCertificateItem3"))); } } - @Test - @Disabled - public void testGetAliases() { - List result = getKeyVaultClient().getAliases(); - assertNotNull(result); - } - - @Test - @Disabled - public void testGetCertificate() { - Certificate certificate = getKeyVaultClient().getCertificate("myalias"); - assertNotNull(certificate); - } - - @Test - @Disabled - public void testGetKey() { - assertNull(getKeyVaultClient().getKey("myalias", null)); - } - - private KeyVaultClient getKeyVaultClient() { - String keyVaultUri = System.getProperty("azure.keyvault.uri"); - String tenantId = System.getProperty("azure.keyvault.tenant-id"); - String clientId = System.getProperty("azure.keyvault.client-id"); - String clientSecret = System.getProperty("azure.keyvault.client-secret"); - boolean disableChallengeResourceVerification - = Boolean.parseBoolean(System.getProperty("azure.keyvault.disable-challenge-resource-verification")); - - return new KeyVaultClient(keyVaultUri, tenantId, clientId, clientSecret, null, - disableChallengeResourceVerification); - } - @Test public void testCacheToken() { try (MockedStatic tokenUtilMockedStatic = Mockito.mockStatic(AccessTokenUtil.class); @@ -205,4 +172,100 @@ public void testCacheTokenExpired() { tokenUtilMockedStatic.verify(() -> AccessTokenUtil.getAccessToken(anyString(), anyString()), times(2)); } } + + @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"); + + CertificateListResult certificateListResult = new CertificateListResult(); + certificateListResult.setValue(Arrays.asList(fakeCertificateItem)); + + 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); + + List result = keyVaultClient.getAliases(); + + // 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")); + } + } + + @EnabledIfEnvironmentVariable(named = "AZURE_KEYVAULT_CERTIFICATE_NAME", matches = "myalias") + @Test + public void testKeyVaultClients() { + String accessToken = PropertyConvertorUtils.getPropertyValue("AZURE_KEYVAULT_ACCESS_TOKEN"); + KeyVaultClient keyVaultClient; + if (accessToken != null && !accessToken.isEmpty()) { + keyVaultClient = new KeyVaultClient( + PropertyConvertorUtils.getPropertyValue("AZURE_KEYVAULT_ENDPOINT"), + null, + null, + null, + null, + accessToken, + false); + + } else { + keyVaultClient = new KeyVaultClient( + PropertyConvertorUtils.getPropertyValue("AZURE_KEYVAULT_ENDPOINT"), + PropertyConvertorUtils.getPropertyValue("AZURE_KEYVAULT_TENANT_ID"), + PropertyConvertorUtils.getPropertyValue("AZURE_KEYVAULT_CLIENT_ID"), + PropertyConvertorUtils.getPropertyValue("AZURE_KEYVAULT_CLIENT_SECRET")); + } + String certificateName = PropertyConvertorUtils.getPropertyValue("AZURE_KEYVAULT_CERTIFICATE_NAME"); + + assertTrue(keyVaultClient.getAliases().contains(certificateName)); + assertNotNull(keyVaultClient.getCertificate(certificateName)); + assertNotNull(keyVaultClient.getCertificateChain(certificateName)); + assertNotNull(keyVaultClient.getKey(certificateName, null)); + } }