diff --git a/.github/workflows/entraid_integration.yml b/.github/workflows/entraid_integration.yml index 076c0bc..0cbb6e1 100644 --- a/.github/workflows/entraid_integration.yml +++ b/.github/workflows/entraid_integration.yml @@ -64,3 +64,4 @@ jobs: AZURE_CERT: ${{secrets.AZURE_CERT}} AZURE_PRIVATE_KEY: ${{secrets.AZURE_PRIVATE_KEY}} AZURE_REDIS_SCOPES: ${{secrets.AZURE_REDIS_SCOPES}} + AZURE_TENANT_ID: ${{secrets.AZURE_TENANT_ID}} diff --git a/core/src/main/java/redis/clients/authentication/core/Dispatcher.java b/core/src/main/java/redis/clients/authentication/core/Dispatcher.java index 58f6de4..5d6c653 100644 --- a/core/src/main/java/redis/clients/authentication/core/Dispatcher.java +++ b/core/src/main/java/redis/clients/authentication/core/Dispatcher.java @@ -1,5 +1,8 @@ /* - * Copyright 2024, Redis Ltd. and Contributors All rights reserved. Licensed under the MIT License. + * Copyright 2024, Redis Ltd. and Contributors + * All rights reserved. + * + * Licensed under the MIT License. */ package redis.clients.authentication.core; diff --git a/core/src/main/java/redis/clients/authentication/core/RenewalScheduler.java b/core/src/main/java/redis/clients/authentication/core/RenewalScheduler.java index 97d70d3..e42a5ad 100644 --- a/core/src/main/java/redis/clients/authentication/core/RenewalScheduler.java +++ b/core/src/main/java/redis/clients/authentication/core/RenewalScheduler.java @@ -1,5 +1,8 @@ /* - * Copyright 2024, Redis Ltd. and Contributors All rights reserved. Licensed under the MIT License. + * Copyright 2024, Redis Ltd. and Contributors + * All rights reserved. + * + * Licensed under the MIT License. */ package redis.clients.authentication.core; diff --git a/core/src/main/java/redis/clients/authentication/core/TokenManager.java b/core/src/main/java/redis/clients/authentication/core/TokenManager.java index 30bc1b4..1966207 100644 --- a/core/src/main/java/redis/clients/authentication/core/TokenManager.java +++ b/core/src/main/java/redis/clients/authentication/core/TokenManager.java @@ -1,5 +1,8 @@ /* - * Copyright 2024, Redis Ltd. and Contributors All rights reserved. Licensed under the MIT License. + * Copyright 2024, Redis Ltd. and Contributors + * All rights reserved. + * + * Licensed under the MIT License. */ package redis.clients.authentication.core; diff --git a/entraid/pom.xml b/entraid/pom.xml index d08b08c..4940ecc 100644 --- a/entraid/pom.xml +++ b/entraid/pom.xml @@ -67,6 +67,11 @@ msal4j 1.17.2 + + com.azure + azure-identity + 1.15.3 + junit junit diff --git a/entraid/src/main/java/redis/clients/authentication/entraid/AzureIdentityProvider.java b/entraid/src/main/java/redis/clients/authentication/entraid/AzureIdentityProvider.java new file mode 100644 index 0000000..74ec984 --- /dev/null +++ b/entraid/src/main/java/redis/clients/authentication/entraid/AzureIdentityProvider.java @@ -0,0 +1,68 @@ +/* + * Copyright 2024, Redis Ltd. and Contributors + * All rights reserved. + * + * Licensed under the MIT License. + */ +package redis.clients.authentication.entraid; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Set; +import java.util.function.Supplier; + +import com.azure.core.credential.AccessToken; +import com.azure.core.credential.TokenRequestContext; +import com.azure.identity.DefaultAzureCredential; +import redis.clients.authentication.core.IdentityProvider; +import redis.clients.authentication.core.Token; + +/** + * AzureIdentityProvider is an implementation of the IdentityProvider interface + * that uses Azure's DefaultAzureCredential to obtain access tokens. + * + *

This class is designed to work with Azure's identity platform to provide + * authentication tokens for accessing Azure resources. It uses a + * DefaultAzureCredential to request tokens with specified scopes and a timeout(in milliseconds). + * For most cases you will not need to use it directly since AzureTokenAuthConfigBuilder + * will do the work for you as shown in the example below: + *

+ * {@code
+ * TokenAuthConfig config = AzureTokenAuthConfigBuilder.builder()
+ *          .defaultAzureCredential(new DefaultAzureCredential()).build();
+ * }
+ * 
+ *

In you case you need your own implementation for relevant reasons, you can use it as follows: + *

+ * {@code
+ * Set scopes = new HashSet<>(Arrays.asList("https://redis.azure.com/.default"));
+ * AzureIdentityProvider provider = new AzureIdentityProvider(
+ *      new DefaultAzureCredentialBuilder().build(), scopes, 5000);
+ * TokenAuthConfig config = AzureTokenAuthConfigBuilder.builder().identityProviderConfig(()-> provider)).build();
+ * }
+ * 
+ * + *

Thread Safety: This class is thread-safe as long as the provided + * DefaultAzureCredential is thread-safe. + * + * @see redis.clients.authentication.entraid.AzureTokenAuthConfigBuilder + * @see com.azure.identity.DefaultAzureCredentialBuilder + */ + +public final class AzureIdentityProvider implements IdentityProvider { + + private Supplier accessTokenSupplier; + + public AzureIdentityProvider(DefaultAzureCredential defaultAzureCredential, Set scopes, + int timeout) { + TokenRequestContext ctx = new TokenRequestContext() + .setScopes(new ArrayList(scopes)); + accessTokenSupplier = () -> defaultAzureCredential.getToken(ctx) + .block(Duration.ofMillis(timeout)); + } + + @Override + public Token requestToken() { + return new JWToken(accessTokenSupplier.get().getToken()); + } +} diff --git a/entraid/src/main/java/redis/clients/authentication/entraid/AzureIdentityProviderConfig.java b/entraid/src/main/java/redis/clients/authentication/entraid/AzureIdentityProviderConfig.java new file mode 100644 index 0000000..08110d5 --- /dev/null +++ b/entraid/src/main/java/redis/clients/authentication/entraid/AzureIdentityProviderConfig.java @@ -0,0 +1,62 @@ +/* + * Copyright 2024, Redis Ltd. and Contributors + * All rights reserved. + * + * Licensed under the MIT License. + */ +package redis.clients.authentication.entraid; + +import java.util.Set; +import java.util.function.Supplier; + +import com.azure.identity.DefaultAzureCredential; + +import redis.clients.authentication.core.IdentityProvider; +import redis.clients.authentication.core.IdentityProviderConfig; + +/** + * Configuration class for Azure Identity Provider. + * This class implements the {@link IdentityProviderConfig} interface and provides + * a configuration for creating an {@link AzureIdentityProvider} instance. + * + *

This class uses {@link DefaultAzureCredential} for authentication and allows + * specifying scopes and a timeout(in milliseconds) for the identity provider.

+ * For most cases you will not need to use it directly since AzureTokenAuthConfigBuilder + * will do the work for you as shown in the example below: + *
+ * {@code
+ * TokenAuthConfig config = AzureTokenAuthConfigBuilder.builder()
+ *          .defaultAzureCredential(new DefaultAzureCredentialBuilder()).build();
+ * } 
+ * 
+ *

In you case you need your own implementation for relevant reasons, you can use it as follows: + *

+ * {@code
+ * DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
+ * Set scopes = Set.of("https://redis.azure.com/.default");
+ * AzureIdentityProviderConfig azureIDPConfig = new AzureIdentityProviderConfig(credential, scopes, 5000);
+ * TokenAuthConfig config = AzureTokenAuthConfigBuilder.builder().identityProviderConfig(azureIDPConfig).build();
+ * }
+ * 
+ * + * For more information and details on how to use, please see: + * https://github.com/redis/jedis/blob/master/docs/advanced-usage.md#token-based-authentication + * https://github.com/redis/lettuce/blob/main/docs/user-guide/connecting-redis.md#microsoft-entra-id-authentication + * + * @see IdentityProviderConfig + * @see AzureIdentityProvider + * @see DefaultAzureCredential + */ +public final class AzureIdentityProviderConfig implements IdentityProviderConfig { + + private final Supplier providerSupplier; + + public AzureIdentityProviderConfig(DefaultAzureCredential defaultAzureCredential, Set scopes, int timeout) { + providerSupplier = () -> new AzureIdentityProvider(defaultAzureCredential, scopes, timeout); + } + + @Override + public IdentityProvider getProvider() { + return providerSupplier.get(); + } +} diff --git a/entraid/src/main/java/redis/clients/authentication/entraid/AzureTokenAuthConfigBuilder.java b/entraid/src/main/java/redis/clients/authentication/entraid/AzureTokenAuthConfigBuilder.java new file mode 100644 index 0000000..09db995 --- /dev/null +++ b/entraid/src/main/java/redis/clients/authentication/entraid/AzureTokenAuthConfigBuilder.java @@ -0,0 +1,118 @@ +/* + * Copyright 2024, Redis Ltd. and Contributors + * All rights reserved. + * + * Licensed under the MIT License. + */ +package redis.clients.authentication.entraid; + +import java.util.Collections; +import java.util.Set; + +import com.azure.identity.DefaultAzureCredential; + +import redis.clients.authentication.core.TokenAuthConfig; +import redis.clients.authentication.core.TokenManagerConfig; + +/** + * Builder class for configuring Azure Token Authentication via a DefaultAzureCredential. + * It builds a TokenAuthConfig object which can be used to authenticate with Azure resources. + * This class extends {@link TokenAuthConfig.Builder} and implements {@link AutoCloseable}. + * It provides methods to configure various parameters for Azure Token Authentication. + * + *

Default values:

+ *
    + *
  • {@code DEFAULT_EXPIRATION_REFRESH_RATIO}: 0.75F
  • + *
  • {@code DEFAULT_LOWER_REFRESH_BOUND_MILLIS}: 2 * 60 * 1000
  • + *
  • {@code DEFAULT_TOKEN_REQUEST_EXECUTION_TIMEOUT_IN_MS}: 1000
  • + *
  • {@code DEFAULT_MAX_ATTEMPTS_TO_RETRY}: 5
  • + *
  • {@code DEFAULT_DELAY_IN_MS_TO_RETRY}: 100
  • + *
  • {@code DEFAULT_SCOPES}: "https://redis.azure.com/.default"
  • + *
+ * + *

Example usage:

+ *
{@code
+ * AzureTokenAuthConfigBuilder builder = AzureTokenAuthConfigBuilder.builder()
+ *     .defaultAzureCredential(new DefaultAzureCredentialBuilder.build())
+ *     .scopes(Collections.singleton("https://example.com/.default"))
+ *     .tokenRequestExecTimeoutInMs(2000);
+ * TokenAuthConfig config = builder.build();
+ * }
+ * + *

This class is also {@link AutoCloseable}, and resources can be cleaned + * up by calling {@link #close()}.

+ * + * @see TokenAuthConfig.Builder + * @see DefaultAzureCredential + */ +public class AzureTokenAuthConfigBuilder + extends TokenAuthConfig.Builder implements AutoCloseable { + public static final float DEFAULT_EXPIRATION_REFRESH_RATIO = 0.75F; + public static final int DEFAULT_LOWER_REFRESH_BOUND_MILLIS = 2 * 60 * 1000; + public static final int DEFAULT_TOKEN_REQUEST_EXECUTION_TIMEOUT_IN_MS = 1000; + public static final int DEFAULT_MAX_ATTEMPTS_TO_RETRY = 5; + public static final int DEFAULT_DELAY_IN_MS_TO_RETRY = 100; + public static final Set DEFAULT_SCOPES = Collections.singleton("https://redis.azure.com/.default");; + + private DefaultAzureCredential defaultAzureCredential; + private Set scopes = DEFAULT_SCOPES; + private int tokenRequestExecTimeoutInMs = DEFAULT_TOKEN_REQUEST_EXECUTION_TIMEOUT_IN_MS; + + public AzureTokenAuthConfigBuilder() { + this.expirationRefreshRatio(DEFAULT_EXPIRATION_REFRESH_RATIO) + .lowerRefreshBoundMillis(DEFAULT_LOWER_REFRESH_BOUND_MILLIS) + .tokenRequestExecTimeoutInMs(DEFAULT_TOKEN_REQUEST_EXECUTION_TIMEOUT_IN_MS) + .maxAttemptsToRetry(DEFAULT_MAX_ATTEMPTS_TO_RETRY) + .delayInMsToRetry(DEFAULT_DELAY_IN_MS_TO_RETRY); + } + + public AzureTokenAuthConfigBuilder defaultAzureCredential( + DefaultAzureCredential defaultAzureCredential) { + this.defaultAzureCredential = defaultAzureCredential; + return this; + } + + public AzureTokenAuthConfigBuilder scopes(Set scopes) { + this.scopes = scopes; + return this; + } + + @Override + public AzureTokenAuthConfigBuilder tokenRequestExecTimeoutInMs( + int tokenRequestExecTimeoutInMs) { + super.tokenRequestExecTimeoutInMs(tokenRequestExecTimeoutInMs); + this.tokenRequestExecTimeoutInMs = tokenRequestExecTimeoutInMs; + return this; + } + + public TokenAuthConfig build() { + super.identityProviderConfig(new AzureIdentityProviderConfig(defaultAzureCredential, scopes, + tokenRequestExecTimeoutInMs)); + return super.build(); + } + + @Override + public void close() throws Exception { + defaultAzureCredential = null; + scopes = null; + } + + public static AzureTokenAuthConfigBuilder builder() { + return new AzureTokenAuthConfigBuilder(); + } + + public static AzureTokenAuthConfigBuilder from(AzureTokenAuthConfigBuilder sample) { + TokenAuthConfig tokenAuthConfig = TokenAuthConfig.Builder.from(sample).build(); + TokenManagerConfig tokenManagerConfig = tokenAuthConfig.getTokenManagerConfig(); + + AzureTokenAuthConfigBuilder builder = (AzureTokenAuthConfigBuilder) new AzureTokenAuthConfigBuilder() + .expirationRefreshRatio(tokenManagerConfig.getExpirationRefreshRatio()) + .lowerRefreshBoundMillis(tokenManagerConfig.getLowerRefreshBoundMillis()) + .tokenRequestExecTimeoutInMs(tokenManagerConfig.getTokenRequestExecTimeoutInMs()) + .maxAttemptsToRetry(tokenManagerConfig.getRetryPolicy().getMaxAttempts()) + .delayInMsToRetry(tokenManagerConfig.getRetryPolicy().getdelayInMs()) + .identityProviderConfig(tokenAuthConfig.getIdentityProviderConfig()); + builder.scopes = sample.scopes; + return builder; + } +} diff --git a/entraid/src/main/java/redis/clients/authentication/entraid/EntraIDTokenAuthConfigBuilder.java b/entraid/src/main/java/redis/clients/authentication/entraid/EntraIDTokenAuthConfigBuilder.java index 6eeefc4..46942bc 100644 --- a/entraid/src/main/java/redis/clients/authentication/entraid/EntraIDTokenAuthConfigBuilder.java +++ b/entraid/src/main/java/redis/clients/authentication/entraid/EntraIDTokenAuthConfigBuilder.java @@ -18,6 +18,60 @@ import redis.clients.authentication.entraid.ManagedIdentityInfo.UserManagedIdentityType; import redis.clients.authentication.entraid.ServicePrincipalInfo.ServicePrincipalAccess; +/** + * Builder class for configuring EntraID token authentication. + * This class provides methods to set various configuration options for EntraID token authentication. + * It extends the TokenAuthConfig.Builder class and implements AutoCloseable. + * + *

Default values:

+ *
    + *
  • DEFAULT_EXPIRATION_REFRESH_RATIO: 0.75F
  • + *
  • DEFAULT_LOWER_REFRESH_BOUND_MILLIS: 120000 (2 minutes)
  • + *
  • DEFAULT_TOKEN_REQUEST_EXECUTION_TIMEOUT_IN_MS: 1000 (1 second)
  • + *
  • DEFAULT_MAX_ATTEMPTS_TO_RETRY: 5
  • + *
  • DEFAULT_DELAY_IN_MS_TO_RETRY: 100 (0.1 second)
  • + *
+ * + *

Configuration options:

+ *
    + *
  • {@link #clientId(String)}: Sets the client ID.
  • + *
  • {@link #secret(String)}: Sets the client secret and configures access with secret.
  • + *
  • {@link #key(PrivateKey, X509Certificate)}: Sets the private key and certificate, + * and configures access with certificate.
  • + *
  • {@link #authority(String)}: Sets the authority URL.
  • + *
  • {@link #systemAssignedManagedIdentity()}: Configures system-assigned managed identity.
  • + *
  • {@link #userAssignedManagedIdentity(UserManagedIdentityType, String)}: + * Configures user-assigned managed identity.
  • + *
  • {@link #customEntraIdAuthenticationSupplier(Supplier)}: Sets a custom authentication supplier.
  • + *
  • {@link #scopes(Set)}: Sets the scopes for the token request.
  • + *
  • {@link #tokenRequestExecTimeoutInMs(int)}: Sets the token request execution timeout in milliseconds.
  • + *
+ * + *

Usage:

+ *
+ * {@code
+ * EntraIDTokenAuthConfigBuilder builder = EntraIDTokenAuthConfigBuilder.builder()
+ *     .clientId("your-client-id")
+ *     .secret("your-secret")
+ *     .authority("https://login.microsoftonline.com/your-tenant-id")
+ *     .scopes(Set.of("https://redis.azure.com/.default"))
+ *     .build();
+ * }
+ * 
+ * + *

Note:

+ *
    + *
  • Only one of ServicePrincipal, ManagedIdentity or customEntraIdAuthenticationSupplier can be configured.
  • + *
  • Throws RedisEntraIDException if conflicting configurations are provided.
  • + *
+ * For more information and details on how to use, please see: + *

https://github.com/redis/jedis/blob/master/docs/advanced-usage.md#token-based-authentication + *

https://github.com/redis/lettuce/blob/main/docs/user-guide/connecting-redis.md#microsoft-entra-id-authentication + * + * @see TokenAuthConfig.Builder + * @see AutoCloseable + * + */ public class EntraIDTokenAuthConfigBuilder extends TokenAuthConfig.Builder implements AutoCloseable { public static final float DEFAULT_EXPIRATION_REFRESH_RATIO = 0.75F; diff --git a/entraid/src/test/java/redis/clients/authentication/AzureIdentityProviderIntegrationTests.java b/entraid/src/test/java/redis/clients/authentication/AzureIdentityProviderIntegrationTests.java new file mode 100644 index 0000000..2b62a30 --- /dev/null +++ b/entraid/src/test/java/redis/clients/authentication/AzureIdentityProviderIntegrationTests.java @@ -0,0 +1,39 @@ +/* + * Copyright 2024, Redis Ltd. and Contributors + * All rights reserved. + * + * Licensed under the MIT License. + */ +package redis.clients.authentication; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import org.junit.Test; +import com.azure.identity.DefaultAzureCredential; +import com.azure.identity.DefaultAzureCredentialBuilder; + +import redis.clients.authentication.core.Token; +import redis.clients.authentication.entraid.AzureIdentityProvider; +import redis.clients.authentication.entraid.AzureTokenAuthConfigBuilder; + +public class AzureIdentityProviderIntegrationTests { + + @Test + public void requestTokenWithDefaultAzureCredential() { + // ensure environment variables are set + String client_id = System.getenv(TestContext.AZURE_CLIENT_ID); + assertNotNull(client_id); + assertFalse(client_id.isEmpty()); + String clientSecret = System.getenv(TestContext.AZURE_CLIENT_SECRET); + assertNotNull(clientSecret); + assertFalse(clientSecret.isEmpty()); + String tenantId = System.getenv("AZURE_TENANT_ID"); + assertNotNull(tenantId); + assertFalse(tenantId.isEmpty()); + + DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilder().build(); + Token token = new AzureIdentityProvider(defaultAzureCredential, + AzureTokenAuthConfigBuilder.DEFAULT_SCOPES, 2000).requestToken(); + assertNotNull(token.getValue()); + } +} diff --git a/entraid/src/test/java/redis/clients/authentication/AzureIdentityProviderUnitTests.java b/entraid/src/test/java/redis/clients/authentication/AzureIdentityProviderUnitTests.java new file mode 100644 index 0000000..c98879c --- /dev/null +++ b/entraid/src/test/java/redis/clients/authentication/AzureIdentityProviderUnitTests.java @@ -0,0 +1,91 @@ +/* + * Copyright 2024, Redis Ltd. and Contributors + * All rights reserved. + * + * Licensed under the MIT License. + */ +package redis.clients.authentication; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.time.OffsetDateTime; +import java.util.Date; +import java.util.Set; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.MockedConstruction; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.azure.core.credential.AccessToken; +import com.azure.core.credential.TokenRequestContext; +import com.azure.identity.DefaultAzureCredential; + +import reactor.core.publisher.Mono; +import redis.clients.authentication.entraid.AzureIdentityProvider; +import redis.clients.authentication.entraid.AzureIdentityProviderConfig; +import redis.clients.authentication.entraid.AzureTokenAuthConfigBuilder; + +public class AzureIdentityProviderUnitTests { + @Test + public void testAzureTokenAuthConfigBuilder() { + DefaultAzureCredential mockCredential = mock(DefaultAzureCredential.class); + Set scopes = AzureTokenAuthConfigBuilder.DEFAULT_SCOPES; + int timeout = 2000; + + try (MockedConstruction mockedConstructor = mockConstruction( + AzureIdentityProviderConfig.class, + (mock, context) -> { + assertEquals(mockCredential, context.arguments().get(0)); + assertEquals(scopes, context.arguments().get(1)); + assertEquals(timeout, context.arguments().get(2)); + })) { + AzureTokenAuthConfigBuilder.builder().defaultAzureCredential(mockCredential).scopes(scopes) + .tokenRequestExecTimeoutInMs(timeout).build(); + } + } + + public void testAzureIdentityProviderConfig() { + DefaultAzureCredential mockCredential = mock(DefaultAzureCredential.class); + Set scopes = AzureTokenAuthConfigBuilder.DEFAULT_SCOPES; + int timeout = 2000; + + try (MockedConstruction mockedConstructor = mockConstruction( + AzureIdentityProvider.class, + (mock, context) -> { + assertEquals(mockCredential, context.arguments().get(0)); + assertEquals(scopes, context.arguments().get(1)); + assertEquals(timeout, context.arguments().get(2)); + })) { + new AzureIdentityProviderConfig(mockCredential, scopes, timeout).getProvider(); + } + } + + @Test + public void testRequestWithMockCredential() { + String token = JWT.create().withExpiresAt(new Date(System.currentTimeMillis() + - 1000)) + .withClaim("oid", "user1").sign(Algorithm.none()); + + AccessToken t = new AccessToken(token, OffsetDateTime.now()); + Mono monoToken = Mono.just(t); + DefaultAzureCredential mockCredential = mock(DefaultAzureCredential.class); + when(mockCredential.getToken(any(TokenRequestContext.class))).thenReturn(monoToken); + new AzureIdentityProviderConfig(mockCredential, + AzureTokenAuthConfigBuilder.DEFAULT_SCOPES, 0).getProvider().requestToken(); + + ArgumentCaptor argument = ArgumentCaptor.forClass(TokenRequestContext.class); + + verify(mockCredential, atLeast(1)).getToken(argument.capture()); + AzureTokenAuthConfigBuilder.DEFAULT_SCOPES + .forEach((item) -> assertTrue(argument.getValue().getScopes().contains(item))); + } +} diff --git a/entraid/src/test/java/redis/clients/authentication/TestContext.java b/entraid/src/test/java/redis/clients/authentication/TestContext.java index 79c7829..070d25f 100644 --- a/entraid/src/test/java/redis/clients/authentication/TestContext.java +++ b/entraid/src/test/java/redis/clients/authentication/TestContext.java @@ -19,13 +19,13 @@ public class TestContext { - private static final String AZURE_CLIENT_ID = "AZURE_CLIENT_ID"; - private static final String AZURE_AUTHORITY = "AZURE_AUTHORITY"; - private static final String AZURE_CLIENT_SECRET = "AZURE_CLIENT_SECRET"; - private static final String AZURE_PRIVATE_KEY = "AZURE_PRIVATE_KEY"; - private static final String AZURE_CERT = "AZURE_CERT"; - private static final String AZURE_REDIS_SCOPES = "AZURE_REDIS_SCOPES"; - private static final String AZURE_USER_ASSIGNED_MANAGED_IDENTITY_CLIENT_ID = "AZURE_USER_ASSIGNED_MANAGED_IDENTITY_CLIENT_ID"; + public static final String AZURE_CLIENT_ID = "AZURE_CLIENT_ID"; + public static final String AZURE_AUTHORITY = "AZURE_AUTHORITY"; + public static final String AZURE_CLIENT_SECRET = "AZURE_CLIENT_SECRET"; + public static final String AZURE_PRIVATE_KEY = "AZURE_PRIVATE_KEY"; + public static final String AZURE_CERT = "AZURE_CERT"; + public static final String AZURE_REDIS_SCOPES = "AZURE_REDIS_SCOPES"; + public static final String AZURE_USER_ASSIGNED_MANAGED_IDENTITY_CLIENT_ID = "AZURE_USER_ASSIGNED_MANAGED_IDENTITY_CLIENT_ID"; private String clientId; private String authority;