Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sdk/keyvault/azure-security-keyvault-jca/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions sdk/keyvault/azure-security-keyvault-jca/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand All @@ -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);
}

/**
Expand All @@ -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);
}

/**
Expand All @@ -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);
}

/**
Expand All @@ -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;
}

/**
Expand Down Expand Up @@ -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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ public class KeyVaultClient {
*/
private String managedIdentity;

/**
* Stores the provided access token string.
*/
private final String providedAccessToken;

/**
* Stores the token.
*/
Expand All @@ -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);
}

/**
Expand All @@ -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);
}

/**
Expand All @@ -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);

Expand All @@ -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;
}

Expand All @@ -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);
}

Expand All @@ -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;
Expand All @@ -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");
Expand All @@ -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;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,23 @@ public class AccessToken implements JsonSerializable<AccessToken> {
*/
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.
*
Expand Down

This file was deleted.

Loading
Loading