diff --git a/sdk/identity/azure-identity/CHANGELOG.md b/sdk/identity/azure-identity/CHANGELOG.md index 319daf306b5ce..e15f79691cce1 100644 --- a/sdk/identity/azure-identity/CHANGELOG.md +++ b/sdk/identity/azure-identity/CHANGELOG.md @@ -1,21 +1,5 @@ # Release History -## 1.12.0-beta.2 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes - -## 1.12.0-beta.1 (2024-02-12) - -### Features Added -- Added expires_on parsing support to `AzureCliCredential`.([#38406](https://github.com/Azure/azure-sdk-for-java/pull/38406)) -- Added caching support for working credential in `DefaultAzureCredential`. ([#38404](https://github.com/Azure/azure-sdk-for-java/pull/38404)) - ## 1.11.2 (2024-02-05) ### Bugs Fixed diff --git a/sdk/identity/azure-identity/assets.json b/sdk/identity/azure-identity/assets.json deleted file mode 100644 index 07fe94c26141a..0000000000000 --- a/sdk/identity/azure-identity/assets.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "AssetsRepo": "Azure/azure-sdk-assets", - "AssetsRepoPrefixPath": "java", - "TagPrefix": "java/identity/azure-identity", - "Tag": "java/identity/azure-identity_0d969ae2eb" -} diff --git a/sdk/identity/azure-identity/pom.xml b/sdk/identity/azure-identity/pom.xml index 8406340284c20..5c8ad78ce2188 100644 --- a/sdk/identity/azure-identity/pom.xml +++ b/sdk/identity/azure-identity/pom.xml @@ -6,7 +6,7 @@ com.azure azure-identity - 1.12.0-beta.2 + 1.11.2 Microsoft Azure client library for Identity This module contains client library for Microsoft Azure Identity. @@ -33,17 +33,12 @@ com.azure azure-core - 1.47.0 + 1.46.0 com.azure azure-core-http-netty - 1.14.1 - - - com.azure - azure-json - 1.1.0 + 1.14.0 com.microsoft.azure @@ -58,7 +53,7 @@ com.azure azure-core-test - 1.24.0 + 1.23.0 test @@ -100,19 +95,19 @@ redis.clients jedis - 5.1.0 + 4.3.1 test io.lettuce lettuce-core - 6.3.1.RELEASE + 6.2.0.RELEASE test org.redisson redisson - 3.27.0 + 3.17.0 test diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/ChainedTokenCredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/ChainedTokenCredential.java index dc39713d8e0c8..e88963fab2336 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/ChainedTokenCredential.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/ChainedTokenCredential.java @@ -15,8 +15,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; import java.util.stream.Collectors; /** @@ -58,7 +56,6 @@ public class ChainedTokenCredential implements TokenCredential { private static final ClientLogger LOGGER = new ClientLogger(ChainedTokenCredential.class); private final List credentials; private final String unavailableError = this.getClass().getSimpleName() + " authentication failed. ---> "; - private final AtomicReference selectedCredential; /** * Create an instance of chained token credential that aggregates a list of token @@ -66,7 +63,6 @@ public class ChainedTokenCredential implements TokenCredential { */ ChainedTokenCredential(List credentials) { this.credentials = Collections.unmodifiableList(credentials); - selectedCredential = new AtomicReference<>(); } /** @@ -83,48 +79,35 @@ public class ChainedTokenCredential implements TokenCredential { @Override public Mono getToken(TokenRequestContext request) { List exceptions = new ArrayList<>(4); - Mono accessTokenMono; - if (selectedCredential.get() != null) { - accessTokenMono = Mono.defer(() -> selectedCredential.get().getToken(request) - .doOnNext(t -> logTokenMessage("Azure Identity => Returning token from cached credential {}", - selectedCredential.get())) - .onErrorResume(Exception.class, handleExceptionAsync(exceptions, - selectedCredential.get(), "Azure Identity => Cached credential {} is unavailable."))); - } else { - accessTokenMono = Flux.fromIterable(credentials) - .flatMap(p -> p.getToken(request) - .doOnNext(t -> { - logTokenMessage("Azure Identity => Attempted credential {} returns a token", p); - selectedCredential.set(p); - }).onErrorResume(Exception.class, handleExceptionAsync(exceptions, p, - "Azure Identity => Attempted credential {} is unavailable.")), 1) - .next(); - } - return accessTokenMono.switchIfEmpty(Mono.defer(() -> { - // Chain Exceptions. - CredentialUnavailableException last = exceptions.get(exceptions.size() - 1); - for (int z = exceptions.size() - 2; z >= 0; z--) { - CredentialUnavailableException current = exceptions.get(z); - last = new CredentialUnavailableException(current.getMessage() + "\r\n" + last.getMessage() - + (z == 0 ? "To mitigate this issue, please refer to the troubleshooting guidelines here at " - + "https://aka.ms/azure-identity-java-default-azure-credential-troubleshoot" : "")); - } - return Mono.error(last); - })); - } - - private Function> handleExceptionAsync(List exceptions, - TokenCredential p, String logMessage) { - return t -> { - if (!t.getClass().getSimpleName().equals("CredentialUnavailableException")) { - return Mono.error(new ClientAuthenticationException( - getCredUnavailableMessage(p, t), - null, t)); - } - exceptions.add((CredentialUnavailableException) t); - logTokenMessage(logMessage, p); - return Mono.empty(); - }; + return Flux.fromIterable(credentials) + .flatMap(p -> p.getToken(request) + .doOnNext(t -> LOGGER.info("Azure Identity => Attempted credential {} returns a token", + p.getClass().getSimpleName())) + .onErrorResume(Exception.class, t -> { + if (!t.getClass().getSimpleName().equals("CredentialUnavailableException")) { + return Mono.error(new ClientAuthenticationException( + unavailableError + p.getClass().getSimpleName() + + " authentication failed. Error Details: " + t.getMessage(), + null, t)); + } + exceptions.add((CredentialUnavailableException) t); + LOGGER.info("Azure Identity => Attempted credential {} is unavailable.", + p.getClass().getSimpleName()); + return Mono.empty(); + }), 1) + .next() + .switchIfEmpty(Mono.defer(() -> { + // Chain Exceptions. + CredentialUnavailableException last = exceptions.get(exceptions.size() - 1); + for (int z = exceptions.size() - 2; z >= 0; z--) { + CredentialUnavailableException current = exceptions.get(z); + last = new CredentialUnavailableException(current.getMessage() + "\r\n" + last.getMessage() + + (z == 0 ? "To mitigate this issue, please refer to the troubleshooting guidelines here at " + + "https://aka.ms/azure-identity-java-default-azure-credential-troubleshoot" + : "")); + } + return Mono.error(last); + })); } @@ -132,27 +115,22 @@ private Function> handleExceptionAsync(Li public AccessToken getTokenSync(TokenRequestContext request) { List exceptions = new ArrayList<>(4); - if (selectedCredential.get() != null) { + for (TokenCredential credential : credentials) { try { - AccessToken accessToken = selectedCredential.get().getTokenSync(request); - logTokenMessage("Azure Identity => Returning token from cached credential {}", selectedCredential.get()); - return accessToken; + return credential.getTokenSync(request); } catch (Exception e) { - handleExceptionSync(e, selectedCredential.get(), exceptions, - "Azure Identity => Cached credential {} is unavailable.", selectedCredential.get()); - } - } else { - for (TokenCredential credential : credentials) { - try { - AccessToken accessToken = credential.getTokenSync(request); - logTokenMessage("Azure Identity => Attempted credential {} returns a token", credential); - selectedCredential.set(credential); - return accessToken; - - } catch (Exception e) { - handleExceptionSync(e, credential, exceptions, - "Azure Identity => Attempted credential {} is unavailable.", credential); + if (e.getClass() != CredentialUnavailableException.class) { + throw new ClientAuthenticationException( + unavailableError + credential.getClass().getSimpleName() + + " authentication failed. Error Details: " + e.getMessage(), + null, e); + } else { + if (e instanceof CredentialUnavailableException) { + exceptions.add((CredentialUnavailableException) e); + } } + LOGGER.info("Azure Identity => Attempted credential {} is unavailable.", + credential.getClass().getSimpleName()); } } @@ -167,31 +145,6 @@ public AccessToken getTokenSync(TokenRequestContext request) { throw last; } - private void logTokenMessage(String format, TokenCredential selectedCredential) { - LOGGER.info(format, - selectedCredential.getClass().getSimpleName()); - } - - private String getCredUnavailableMessage(TokenCredential p, Exception t) { - return unavailableError + p.getClass().getSimpleName() - + " authentication failed. Error Details: " + t.getMessage(); - } - - private void handleExceptionSync(Exception e, TokenCredential selectedCredential, - List exceptions, String logMessage, - TokenCredential selectedCredential1) { - if (e.getClass() != CredentialUnavailableException.class) { - throw new ClientAuthenticationException( - getCredUnavailableMessage(selectedCredential, e), - null, e); - } else { - if (e instanceof CredentialUnavailableException) { - exceptions.add((CredentialUnavailableException) e); - } - } - logTokenMessage(logMessage, selectedCredential1); - } - WorkloadIdentityCredential getWorkloadIdentityCredentialIfPresent() { List tokenCredentials = this.credentials .stream().filter(tokenCredential -> tokenCredential instanceof WorkloadIdentityCredential) diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java index 920c7a4e740eb..23df9730bcded 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java @@ -349,6 +349,7 @@ public Mono authenticateWithAzureCli(TokenRequestContext request) { ? LoggingUtil.logCredentialUnavailableException(LOGGER, options, (CredentialUnavailableException) e) : LOGGER.logExceptionAsError(e)); } + } /** @@ -610,42 +611,48 @@ public Mono authenticateWithUsernamePassword(TokenRequestContext requ @SuppressWarnings("deprecation") public Mono authenticateWithPublicClientCache(TokenRequestContext request, IAccount account) { return getPublicClientInstance(request).getValue() - .flatMap(pc -> Mono.fromFuture(() -> - acquireTokenFromPublicClientSilently(request, pc, account, false) - ).map(MsalToken::new) + .flatMap(pc -> Mono.fromFuture(() -> { + SilentParameters.SilentParametersBuilder parametersBuilder = SilentParameters.builder( + new HashSet<>(request.getScopes())); + + if (request.isCaeEnabled() && request.getClaims() != null) { + ClaimsRequest customClaimRequest = CustomClaimRequest.formatAsClaimsRequest(request.getClaims()); + parametersBuilder.claims(customClaimRequest); + parametersBuilder.forceRefresh(true); + } + if (account != null) { + parametersBuilder = parametersBuilder.account(account); + } + parametersBuilder.tenant( + IdentityUtil.resolveTenantId(tenantId, request, options)); + try { + return pc.acquireTokenSilently(parametersBuilder.build()); + } catch (MalformedURLException e) { + return getFailedCompletableFuture(LOGGER.logExceptionAsError(new RuntimeException(e))); + } + }).map(MsalToken::new) .filter(t -> OffsetDateTime.now().isBefore(t.getExpiresAt().minus(REFRESH_OFFSET))) - .switchIfEmpty(Mono.fromFuture(() -> - acquireTokenFromPublicClientSilently(request, pc, account, true) - ).map(MsalToken::new)) - ); - } + .switchIfEmpty(Mono.fromFuture(() -> { + SilentParameters.SilentParametersBuilder forceParametersBuilder = SilentParameters.builder( + new HashSet<>(request.getScopes())).forceRefresh(true); - private CompletableFuture acquireTokenFromPublicClientSilently(TokenRequestContext request, - PublicClientApplication pc, - IAccount account, - boolean forceRefresh - ) { - SilentParameters.SilentParametersBuilder parametersBuilder = SilentParameters.builder( - new HashSet<>(request.getScopes())); + if (request.getClaims() != null) { + ClaimsRequest customClaimRequest = CustomClaimRequest + .formatAsClaimsRequest(request.getClaims()); + forceParametersBuilder.claims(customClaimRequest); + } - if (forceRefresh) { - parametersBuilder.forceRefresh(true); - } - if (request.isCaeEnabled() && request.getClaims() != null) { - ClaimsRequest customClaimRequest = CustomClaimRequest.formatAsClaimsRequest(request.getClaims()); - parametersBuilder.claims(customClaimRequest); - parametersBuilder.forceRefresh(true); - } - if (account != null) { - parametersBuilder = parametersBuilder.account(account); - } - parametersBuilder.tenant( - IdentityUtil.resolveTenantId(tenantId, request, options)); - try { - return pc.acquireTokenSilently(parametersBuilder.build()); - } catch (MalformedURLException e) { - return getFailedCompletableFuture(LOGGER.logExceptionAsError(new RuntimeException(e))); - } + if (account != null) { + forceParametersBuilder = forceParametersBuilder.account(account); + } + forceParametersBuilder.tenant( + IdentityUtil.resolveTenantId(tenantId, request, options)); + try { + return pc.acquireTokenSilently(forceParametersBuilder.build()); + } catch (MalformedURLException e) { + return getFailedCompletableFuture(LOGGER.logExceptionAsError(new RuntimeException(e))); + } + }).map(MsalToken::new))); } private SynchronizedAccessor getPublicClientInstance(TokenRequestContext request) { @@ -822,25 +829,16 @@ public Mono authenticateWithBrowserInteraction(TokenRequestContext re } catch (URISyntaxException e) { return Mono.error(LOGGER.logExceptionAsError(new RuntimeException(e))); } + InteractiveRequestParameters.InteractiveRequestParametersBuilder builder = + buildInteractiveRequestParameters(request, loginHint, redirectUri); - if (options.isBrokerEnabled() && options.useOperatingSystemAccount()) { - return getPublicClientInstance(request).getValue().flatMap(pc -> - Mono.fromFuture(() -> - acquireTokenFromPublicClientSilently(request, pc, null, false)). - map(MsalToken::new)); - } else { - - InteractiveRequestParameters.InteractiveRequestParametersBuilder builder = - buildInteractiveRequestParameters(request, loginHint, redirectUri); - - SynchronizedAccessor publicClient = getPublicClientInstance(request); + SynchronizedAccessor publicClient = getPublicClientInstance(request); - Mono acquireToken = publicClient.getValue() - .flatMap(pc -> Mono.fromFuture(() -> pc.acquireToken(builder.build()))); + Mono acquireToken = publicClient.getValue() + .flatMap(pc -> Mono.fromFuture(() -> pc.acquireToken(builder.build()))); - return acquireToken.onErrorMap(t -> new ClientAuthenticationException( - "Failed to acquire token with Interactive Browser Authentication.", null, t)).map(MsalToken::new); - } + return acquireToken.onErrorMap(t -> new ClientAuthenticationException( + "Failed to acquire token with Interactive Browser Authentication.", null, t)).map(MsalToken::new); } /** @@ -948,7 +946,7 @@ private Mono authenticateToArcManagedIdentityEndpoint(String identi String secretKeyPath = realm.substring(separatorIndex + 1); secretKey = new String(Files.readAllBytes(Paths.get(secretKeyPath)), StandardCharsets.UTF_8); - + if (connection != null) { connection.disconnect(); } diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientBase.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientBase.java index de647a175e4fe..e9711db795808 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientBase.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientBase.java @@ -32,12 +32,9 @@ import com.azure.identity.CredentialUnavailableException; import com.azure.identity.DeviceCodeInfo; import com.azure.identity.TokenCachePersistenceOptions; -import com.azure.identity.implementation.models.AzureCliToken; import com.azure.identity.implementation.util.CertificateUtil; import com.azure.identity.implementation.util.IdentityUtil; import com.azure.identity.implementation.util.LoggingUtil; -import com.azure.json.JsonProviders; -import com.azure.json.JsonReader; import com.microsoft.aad.msal4j.AppTokenProviderParameters; import com.microsoft.aad.msal4j.ClaimsRequest; import com.microsoft.aad.msal4j.ClientCredentialFactory; @@ -123,8 +120,6 @@ public abstract class IdentityClientBase { private static final String SDK_NAME = "name"; private static final String SDK_VERSION = "version"; private static final ClientOptions DEFAULT_CLIENT_OPTIONS = new ClientOptions(); - - private final Map properties; @@ -642,13 +637,16 @@ AccessToken getTokenFromAzureCLIAuthentication(StringBuilder azCommand) { LOGGER.verbose("Azure CLI Authentication => A token response was received from Azure CLI, deserializing the" + " response into an Access Token."); - try (JsonReader reader = JsonProviders.createReader(processOutput)) { - AzureCliToken tokenHolder = AzureCliToken.fromJson(reader); - String accessToken = tokenHolder.getAccessToken(); - OffsetDateTime tokenExpiration = tokenHolder.getTokenExpiration(); - token = new AccessToken(accessToken, tokenExpiration); - } - + Map objectMap = SERIALIZER_ADAPTER.deserialize(processOutput, Map.class, + SerializerEncoding.JSON); + String accessToken = objectMap.get("accessToken"); + String time = objectMap.get("expiresOn"); + String timeToSecond = time.substring(0, time.indexOf(".")); + String timeJoinedWithT = String.join("T", timeToSecond.split(" ")); + OffsetDateTime expiresOn = LocalDateTime.parse(timeJoinedWithT, DateTimeFormatter.ISO_LOCAL_DATE_TIME) + .atZone(ZoneId.systemDefault()) + .toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC); + token = new AccessToken(accessToken, expiresOn); } catch (IOException | InterruptedException e) { IllegalStateException ex = new IllegalStateException(redactInfo(e.getMessage())); ex.setStackTrace(e.getStackTrace()); diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientOptions.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientOptions.java index 4350bb5e9ebe1..d31305a71c178 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientOptions.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClientOptions.java @@ -79,7 +79,6 @@ public final class IdentityClientOptions implements Cloneable { private long brokerWindowHandle; private boolean brokerEnabled; private boolean enableMsaPassthrough; - private boolean useOperatingSystemAccount; /** * Creates an instance of IdentityClientOptions with default settings. @@ -782,16 +781,6 @@ public IdentityClientOptions setEnableLegacyMsaPassthrough(boolean enableMsaPass return this; } - /** - * Sets whether to use the logged-in user's account for broker authentication. - * @param useOperatingSystemAccount - * @return the updated client options - */ - public IdentityClientOptions setUseOperatingSystemAccount(boolean useOperatingSystemAccount) { - this.useOperatingSystemAccount = useOperatingSystemAccount; - return this; - } - /** * Gets the status whether MSA passthrough is enabled or not. * @return the flag indicating if MSA passthrough is enabled or not. @@ -800,14 +789,6 @@ public boolean isMsaPassthroughEnabled() { return this.enableMsaPassthrough; } - /** - * Gets the status whether to use the logged-in user's account for broker authentication. - * @return the flag indicating if the logged-in user's account should be used for broker authentication. - */ - public boolean useOperatingSystemAccount() { - return this.useOperatingSystemAccount; - } - public IdentityClientOptions clone() { IdentityClientOptions clone = new IdentityClientOptions() .setAdditionallyAllowedTenants(this.additionallyAllowedTenants) @@ -837,12 +818,9 @@ public IdentityClientOptions clone() { .setPerCallPolicies(this.perCallPolicies) .setPerRetryPolicies(this.perRetryPolicies) .setBrowserCustomizationOptions(this.browserCustomizationOptions) - .setChained(this.isChained); - - if (isBrokerEnabled()) { - clone.setBrokerWindowHandle(this.brokerWindowHandle); - clone.setEnableLegacyMsaPassthrough(this.enableMsaPassthrough); - } + .setChained(this.isChained) + .setBrokerWindowHandle(this.brokerWindowHandle) + .setEnableLegacyMsaPassthrough(this.enableMsaPassthrough); if (!isInstanceDiscoveryEnabled()) { clone.disableInstanceDiscovery(); } diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentitySyncClient.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentitySyncClient.java index 6402042cc0349..dbceb3b7a69ea 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentitySyncClient.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentitySyncClient.java @@ -216,38 +216,53 @@ public AccessToken authenticateWithConfidentialClientCache(TokenRequestContext r @SuppressWarnings("deprecation") public MsalToken authenticateWithPublicClientCache(TokenRequestContext request, IAccount account) { PublicClientApplication pc = getPublicClientInstance(request).getValue(); - MsalToken token = acquireTokenFromPublicClientSilently(request, pc, account, false); - if (OffsetDateTime.now().isAfter(token.getExpiresAt().minus(REFRESH_OFFSET))) { - token = acquireTokenFromPublicClientSilently(request, pc, account, true); - } - return token; - } - - private MsalToken acquireTokenFromPublicClientSilently(TokenRequestContext request, - PublicClientApplication pc, - IAccount account, - boolean forceRefresh) { SilentParameters.SilentParametersBuilder parametersBuilder = SilentParameters.builder( new HashSet<>(request.getScopes())); - if (forceRefresh) { + if (request.getClaims() != null) { + ClaimsRequest customClaimRequest = CustomClaimRequest.formatAsClaimsRequest(request.getClaims()); + parametersBuilder.claims(customClaimRequest); parametersBuilder.forceRefresh(true); } + if (account != null) { + parametersBuilder = parametersBuilder.account(account); + } + parametersBuilder.tenant( + IdentityUtil.resolveTenantId(tenantId, request, options)); + try { + MsalToken accessToken = new MsalToken(pc.acquireTokenSilently(parametersBuilder.build()).get()); + if (OffsetDateTime.now().isBefore(accessToken.getExpiresAt().minus(REFRESH_OFFSET))) { + return accessToken; + } + } catch (MalformedURLException e) { + throw LOGGER.logExceptionAsError(new RuntimeException(e.getMessage(), e)); + } catch (ExecutionException | InterruptedException e) { + // Cache misses should not throw an exception, but should log. + if (e.getMessage().contains("Token not found in the cache")) { + LOGGER.verbose("Token not found in the MSAL cache."); + return null; + } else { + throw LOGGER.logExceptionAsError(new ClientAuthenticationException(e.getMessage(), null, e)); + } + } + + SilentParameters.SilentParametersBuilder forceParametersBuilder = SilentParameters.builder( + new HashSet<>(request.getScopes())).forceRefresh(true); + if (request.isCaeEnabled() && request.getClaims() != null) { ClaimsRequest customClaimRequest = CustomClaimRequest .formatAsClaimsRequest(request.getClaims()); - parametersBuilder.claims(customClaimRequest); - parametersBuilder.forceRefresh(true); + forceParametersBuilder.claims(customClaimRequest); } if (account != null) { - parametersBuilder = parametersBuilder.account(account); + forceParametersBuilder = forceParametersBuilder.account(account); } - parametersBuilder.tenant( + forceParametersBuilder.tenant( IdentityUtil.resolveTenantId(tenantId, request, options)); try { - return new MsalToken(pc.acquireTokenSilently(parametersBuilder.build()).get()); + return new MsalToken(pc.acquireTokenSilently(forceParametersBuilder.build()).get()); } catch (MalformedURLException e) { throw LOGGER.logExceptionAsError(new RuntimeException(e.getMessage(), e)); } catch (ExecutionException | InterruptedException e) { @@ -335,23 +350,15 @@ public MsalToken authenticateWithBrowserInteraction(TokenRequestContext request, } catch (URISyntaxException e) { throw LOGGER.logExceptionAsError(new RuntimeException(e)); } - PublicClientApplication pc = getPublicClientInstance(request).getValue(); - if (options.isBrokerEnabled() && options.useOperatingSystemAccount()) { - return acquireTokenFromPublicClientSilently(request, - pc, - null, - false); - } else { - InteractiveRequestParameters.InteractiveRequestParametersBuilder builder = - buildInteractiveRequestParameters(request, loginHint, redirectUri); - - try { - return new MsalToken(pc.acquireToken(builder.build()).get()); - } catch (Exception e) { - throw LOGGER.logExceptionAsError(new ClientAuthenticationException( - "Failed to acquire token with Interactive Browser Authentication.", null, e)); - } + InteractiveRequestParameters.InteractiveRequestParametersBuilder builder = + buildInteractiveRequestParameters(request, loginHint, redirectUri); + PublicClientApplication pc = getPublicClientInstance(request).getValue(); + try { + return new MsalToken(pc.acquireToken(builder.build()).get()); + } catch (Exception e) { + throw LOGGER.logExceptionAsError(new ClientAuthenticationException( + "Failed to acquire token with Interactive Browser Authentication.", null, e)); } } diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/models/AzureCliToken.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/models/AzureCliToken.java deleted file mode 100644 index 0a792786ed4bd..0000000000000 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/models/AzureCliToken.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.implementation.models; - -import com.azure.json.JsonReader; -import com.azure.json.JsonSerializable; -import com.azure.json.JsonToken; -import com.azure.json.JsonWriter; - -import java.io.IOException; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.OffsetDateTime; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; - -/** - * A wrapper class for deserializing a token payload returned from the Azure CLI. - */ -public final class AzureCliToken implements JsonSerializable { - private String accessToken; - private String expiresOn; - private Long expiresOnUnixTime; - private String subscription; - private String tenant; - private String tokenType; - private OffsetDateTime tokenExpiry; - - public String getAccessToken() { - return accessToken; - } - - public String getExpiresOn() { - return expiresOn; - } - - public Long getExpiresOnUnixTime() { - return expiresOnUnixTime; - } - - public String getSubscription() { - return subscription; - } - - public String getTenant() { - return tenant; - } - - public String getTokenType() { - return tokenType; - } - - public OffsetDateTime getTokenExpiration() { - return tokenExpiry; - } - - private static OffsetDateTime parseExpiresOnTime(String time) { - OffsetDateTime tokenExpiry; - // parse the incoming date: 2024-02-28 12:05:53.000000 - tokenExpiry = LocalDateTime.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS")) - .atZone(ZoneId.systemDefault()) - .toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC); - return tokenExpiry; - } - - public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { - jsonWriter.writeStartObject(); - jsonWriter.writeStringField("accessToken", accessToken); - jsonWriter.writeStringField("expiresOn", expiresOn); - jsonWriter.writeNumberField("expires_on", expiresOnUnixTime); - jsonWriter.writeStringField("subscription", subscription); - jsonWriter.writeStringField("tenant", tenant); - jsonWriter.writeStringField("tokenType", tokenType); - jsonWriter.writeEndObject(); - return jsonWriter; - } - - public static AzureCliToken fromJson(JsonReader jsonReader) throws IOException { - return jsonReader.readObject(reader -> { - AzureCliToken tokenHolder = new AzureCliToken(); - while (reader.nextToken() != JsonToken.END_OBJECT) { - String fieldName = reader.getFieldName(); - reader.nextToken(); - if ("accessToken".equals(fieldName)) { - tokenHolder.accessToken = reader.getString(); - } else if ("expiresOn".equals(fieldName)) { - tokenHolder.expiresOn = reader.getString(); - } else if ("expires_on".equals(fieldName)) { - tokenHolder.expiresOnUnixTime = reader.getLong(); - } else if ("subscription".equals(fieldName)) { - tokenHolder.subscription = reader.getString(); - } else if ("tenant".equals(fieldName)) { - tokenHolder.tenant = reader.getString(); - } else if ("tokenType".equals(fieldName)) { - tokenHolder.tokenType = reader.getString(); - } else { - reader.skipChildren(); - } - } - - if (tokenHolder.expiresOnUnixTime != null) { - tokenHolder.tokenExpiry = Instant.ofEpochSecond(tokenHolder.getExpiresOnUnixTime()).atOffset(ZoneOffset.UTC); - } else { - tokenHolder.tokenExpiry = parseExpiresOnTime(tokenHolder.getExpiresOn()); - } - - return tokenHolder; - }); - } -} diff --git a/sdk/identity/azure-identity/src/main/java/module-info.java b/sdk/identity/azure-identity/src/main/java/module-info.java index 2fe33708a54fe..b1de0b99a508d 100644 --- a/sdk/identity/azure-identity/src/main/java/module-info.java +++ b/sdk/identity/azure-identity/src/main/java/module-info.java @@ -3,7 +3,6 @@ module com.azure.identity { requires transitive com.azure.core; - requires com.azure.json; requires com.microsoft.aad.msal4j; requires msal4j.persistence.extension; diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/Azure-AAD-Authentication-With-Jedis.md b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/Azure-AAD-Authentication-With-Jedis.md index a0c04da109741..eb2ad78a17451 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/Azure-AAD-Authentication-With-Jedis.md +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/Azure-AAD-Authentication-With-Jedis.md @@ -18,13 +18,13 @@ com.azure azure-identity - 1.11.2 + 1.8.2 redis.clients jedis - 5.1.0 + 4.3.2 ``` @@ -57,7 +57,7 @@ DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilde // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. String token = defaultAzureCredential .getToken(new TokenRequestContext() - .addScopes("https://redis.azure.com/.default")).block().getToken(); + .addScopes("https://*.cacheinfra.windows.net:10225/appid/.default")).block().getToken(); // SSL connection is required. boolean useSsl = true; @@ -103,7 +103,7 @@ DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilde // Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password. // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. -TokenRequestContext trc = new TokenRequestContext().addScopes("https://redis.azure.com/.default"); +TokenRequestContext trc = new TokenRequestContext().addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); AccessToken accessToken = getAccessToken(defaultAzureCredential, trc); // SSL connection is required. @@ -169,7 +169,7 @@ DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilde // Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password. // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. -TokenRequestContext trc = new TokenRequestContext().addScopes("https://redis.azure.com/.default"); +TokenRequestContext trc = new TokenRequestContext().addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); TokenRefreshCache tokenRefreshCache = new TokenRefreshCache(defaultAzureCredential, trc); AccessToken accessToken = tokenRefreshCache.getAccessToken(); @@ -374,7 +374,7 @@ jedisClient.close(); In this error scenario, the username provided and the access token used as password are not compatible. To mitigate this error, navigate to your Azure Cache for Redis resource in the Azure portal. Confirm that: * In **Data Access Configuration**, you've assigned the required role to your user/service principal identity. -* Under **Authentication** -> **Microsoft Entra Authentication** category the **Enable Microsoft Entra Authentication** box is selected. If not, select it and select the **Save** button. +* In **Advanced settings**, the **Microsoft Entra Authentication** box is selected. If not, select it and select the **Save** button. ##### Permissions not granted / NOPERM Error In this error scenario, the authentication was successful, but your registered user/service principal is not granted the RBAC permission to perform the action. diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/Authenticator.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/Authenticator.java index 1cbbd276baf9f..14d753e82fc0f 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/Authenticator.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/Authenticator.java @@ -27,7 +27,7 @@ class Authenticator { this.username = username; this.tokenCache = tokenCache; this.tokenRequestContext = new TokenRequestContext() - .addScopes("https://redis.azure.com/.default"); + .addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); lock = new ReentrantLock(); } diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/AzureJedisClient.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/AzureJedisClient.java index 28a58b53a40f9..fd15df24d92ff 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/AzureJedisClient.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/AzureJedisClient.java @@ -12,7 +12,6 @@ import redis.clients.jedis.exceptions.JedisException; import redis.clients.jedis.params.*; import redis.clients.jedis.resps.*; -import redis.clients.jedis.util.KeyValue; import java.util.List; import java.util.Map; @@ -276,6 +275,14 @@ public long bitop(BitOP op, String destKey, String... srcKeys) { return apiManager.execute(() -> jedis.bitop(op, destKey, srcKeys), this); } + /** + * {@inheritDoc} + */ + public LCSMatchResult strAlgoLCSKeys(String keyA, String keyB, StrAlgoLCSParams params) { + return apiManager.execute(() -> jedis.strAlgoLCSKeys(keyA, keyB, params), this); + } + + /** * {@inheritDoc} */ @@ -338,6 +345,13 @@ public byte[] echo(byte[] arg) { return new byte[0]; } + /** + * {@inheritDoc} + */ + public String quit() { + return apiManager.execute(() -> jedis.quit(), this); + } + /** * {@inheritDoc} */ @@ -1012,7 +1026,7 @@ public List hrandfield(String key, long count) { /** * {@inheritDoc} */ - public List> hrandfieldWithValues(String key, long count) { + public Map hrandfieldWithValues(String key, long count) { return apiManager.execute(() -> jedis.hrandfieldWithValues(key, count), this); } @@ -1467,7 +1481,7 @@ public List blpop(int timeout, String key) { /** * {@inheritDoc} */ - public redis.clients.jedis.util.KeyValue blpop(double timeout, String key) { + public KeyedListElement blpop(double timeout, String key) { return apiManager.execute(() -> jedis.blpop(timeout, key), this); } @@ -1481,7 +1495,7 @@ public List brpop(int timeout, String key) { /** * {@inheritDoc} */ - public KeyValue brpop(double timeout, String key) { + public KeyedListElement brpop(double timeout, String key) { return apiManager.execute(() -> jedis.brpop(timeout, key), this); } @@ -1495,7 +1509,7 @@ public List blpop(int timeout, String... keys) { /** * {@inheritDoc} */ - public KeyValue blpop(double timeout, String... keys) { + public KeyedListElement blpop(double timeout, String... keys) { return apiManager.execute(() -> jedis.blpop(timeout, keys), this); } @@ -1509,7 +1523,7 @@ public List brpop(int timeout, String... keys) { /** * {@inheritDoc} */ - public KeyValue brpop(double timeout, String... keys) { + public KeyedListElement brpop(double timeout, String... keys) { return apiManager.execute(() -> jedis.brpop(timeout, keys), this); } @@ -2076,28 +2090,28 @@ public ScanResult zscan(String key, String cursor, ScanParams params) { /** * {@inheritDoc} */ - public KeyValue bzpopmax(double timeout, String... keys) { + public KeyedZSetElement bzpopmax(double timeout, String... keys) { return apiManager.execute(() -> jedis.bzpopmax(timeout, keys), this); } /** * {@inheritDoc} */ - public KeyValue bzpopmin(double timeout, String... keys) { + public KeyedZSetElement bzpopmin(double timeout, String... keys) { return apiManager.execute(() -> jedis.bzpopmin(timeout, keys), this); } /** * {@inheritDoc} */ - public List zdiff(String... keys) { + public Set zdiff(String... keys) { return apiManager.execute(() -> jedis.zdiff(keys), this); } /** * {@inheritDoc} */ - public List zdiffWithScores(String... keys) { + public Set zdiffWithScores(String... keys) { return apiManager.execute(() -> jedis.zdiffWithScores(keys), this); } @@ -2125,28 +2139,28 @@ public long zinterstore(String dstkey, ZParams params, String... sets) { /** * {@inheritDoc} */ - public List zinter(ZParams params, String... keys) { + public Set zinter(ZParams params, String... keys) { return apiManager.execute(() -> jedis.zinter(params, keys), this); } /** * {@inheritDoc} */ - public List zinterWithScores(ZParams params, String... keys) { + public Set zinterWithScores(ZParams params, String... keys) { return apiManager.execute(() -> jedis.zinterWithScores(params, keys), this); } /** * {@inheritDoc} */ - public List zunion(ZParams params, String... keys) { + public Set zunion(ZParams params, String... keys) { return apiManager.execute(() -> jedis.zunion(params, keys), this); } /** * {@inheritDoc} */ - public List zunionWithScores(ZParams params, String... keys) { + public Set zunionWithScores(ZParams params, String... keys) { return apiManager.execute(() -> jedis.zunionWithScores(params, keys), this); } @@ -2284,6 +2298,20 @@ public StreamPendingSummary xpending(String key, String groupname) { return apiManager.execute(() -> jedis.xpending(key, groupname), this); } + /** + * {@inheritDoc} + */ + public List xpending(String key, String groupname, StreamEntryID start, StreamEntryID end, int count, String consumername) { + return apiManager.execute(() -> jedis.xpending(key, groupname, start, end, count, consumername), this); + } + + /** + * {@inheritDoc} + */ + public List xpending(String key, String groupname, XPendingParams params) { + return apiManager.execute(() -> jedis.xpending(key, groupname, params), this); + } + /** * {@inheritDoc} */ @@ -2340,6 +2368,13 @@ public StreamInfo xinfoStream(String key) { return apiManager.execute(() -> jedis.xinfoStream(key), this); } + /** + * {@inheritDoc} + */ + public List xinfoGroup(String key) { + return apiManager.execute(() -> jedis.xinfoGroup(key), this); + } + /** * {@inheritDoc} */ diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/sample/AuthenticateWithTokenCache.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/sample/AuthenticateWithTokenCache.java index e43dc1264115f..fd8c98ca17939 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/sample/AuthenticateWithTokenCache.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/sample/AuthenticateWithTokenCache.java @@ -27,7 +27,7 @@ public static void main(String[] args) { // Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password. // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. - TokenRequestContext trc = new TokenRequestContext().addScopes("https://redis.azure.com/.default"); + TokenRequestContext trc = new TokenRequestContext().addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); TokenRefreshCache tokenRefreshCache = new TokenRefreshCache(defaultAzureCredential, trc); AccessToken accessToken = tokenRefreshCache.getAccessToken(); diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/sample/HandleReauthentication.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/sample/HandleReauthentication.java index 1ebdbfcee43b6..20e3d756f1a70 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/sample/HandleReauthentication.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/sample/HandleReauthentication.java @@ -20,7 +20,7 @@ public static void main(String[] args) { // Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password. // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. - TokenRequestContext trc = new TokenRequestContext().addScopes("https://redis.azure.com/.default"); + TokenRequestContext trc = new TokenRequestContext().addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); AccessToken accessToken = getAccessToken(defaultAzureCredential, trc); // SSL connection is required. diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/sample/HellloWorld.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/sample/HellloWorld.java index 8804fd3d46a64..8d892c409beae 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/sample/HellloWorld.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Jedis/java/com/azure/jedis/sample/HellloWorld.java @@ -19,7 +19,7 @@ public static void main(String[] args) { // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. String token = defaultAzureCredential .getToken(new TokenRequestContext() - .addScopes("https://redis.azure.com/.default")).block().getToken(); + .addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default")).block().getToken(); // SSL connection is required. boolean useSsl = true; diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/Azure-AAD-Authentication-With-Lettuce.md b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/Azure-AAD-Authentication-With-Lettuce.md index 5efc923c9f76c..2125211bca6cf 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/Azure-AAD-Authentication-With-Lettuce.md +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/Azure-AAD-Authentication-With-Lettuce.md @@ -17,13 +17,13 @@ com.azure azure-identity - 1.11.2 + 1.8.2 io.lettuce - lettuce-core - 6.3.1.RELEASE + lettuce-core + 6.2.4.RELEASE ``` @@ -69,7 +69,7 @@ Integrate the logic in your application code to fetch a Microsoft Entra access t io.lettuce lettuce-core - 6.3.1.RELEASE + 6.2.4.RELEASE ``` @@ -220,7 +220,7 @@ Integrate the logic in your application code to fetch a Microsoft Entra access t io.lettuce lettuce-core - 6.3.1.RELEASE + 6.2.4.RELEASE ``` @@ -291,7 +291,7 @@ private static RedisClient createLettuceRedisClient(String hostName, int port, S public static class AzureRedisCredentials implements RedisCredentials { // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. private TokenRequestContext tokenRequestContext = new TokenRequestContext() - .addScopes("https://redis.azure.com/.default"); + .addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); private TokenCredential tokenCredential; private final String username; @@ -346,7 +346,7 @@ DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilde // Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password. // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. -TokenRequestContext trc = new TokenRequestContext().addScopes("https://redis.azure.com/.default"); +TokenRequestContext trc = new TokenRequestContext().addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); AccessToken accessToken = getAccessToken(defaultAzureCredential, trc); // Host Name, Port, Username, and Microsoft Entra token are required here. @@ -426,7 +426,7 @@ Integrate the logic in your application code to fetch a Microsoft Entra access t io.lettuce lettuce-core - 6.3.1.RELEASE + 6.2.4.RELEASE ``` @@ -510,7 +510,7 @@ private static RedisClient createLettuceRedisClient(String hostName, int port, R */ public static class AzureRedisCredentials implements RedisCredentials { private TokenRequestContext tokenRequestContext = new TokenRequestContext() - .addScopes("https://redis.azure.com/.default"); + .addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); private TokenCredential tokenCredential; private TokenRefreshCache refreshCache; private final String username; @@ -653,7 +653,7 @@ DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilde // Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password. // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. -TokenRequestContext trc = new TokenRequestContext().addScopes("https://redis.azure.com/.default"); +TokenRequestContext trc = new TokenRequestContext().addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); // Instantiate the Token Refresh Cache, this cache will proactively refresh the access token 2 minutes before expiry. TokenRefreshCache tokenRefreshCache = new TokenRefreshCache(defaultAzureCredential, trc); @@ -778,7 +778,7 @@ public static class TokenRefreshCache { In this error scenario, the username provided and the access token used as password are not compatible. To mitigate this error, navigate to your Azure Cache for Redis resource in the Azure portal. Confirm that: * In **Data Access Configuration**, you've assigned the required role to your user/service principal identity. -* Under **Authentication** -> **Microsoft Entra Authentication** category the **Enable Microsoft Entra Authentication** box is selected. If not, select it and select the **Save** button. +* In **Advanced settings**, the **Microsoft Entra Authentication** box is selected. If not, select it and select the **Save** button. ##### Permissions not granted / NOPERM Error In this error scenario, the authentication was successful, but your registered user/service principal is not granted the RBAC permission to perform the action. diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/AuthenticateWithTokenCache.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/AuthenticateWithTokenCache.java index 9ea9f7d48a55b..e635ec6459d40 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/AuthenticateWithTokenCache.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/AuthenticateWithTokenCache.java @@ -33,7 +33,7 @@ public static void main(String[] args) { // Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password. // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. - TokenRequestContext trc = new TokenRequestContext().addScopes("https://redis.azure.com/.default"); + TokenRequestContext trc = new TokenRequestContext().addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); // Instantiate the Token Refresh Cache, this cache will proactively refresh the access token 2 - 5 minutes before expiry. TokenRefreshCache tokenRefreshCache = new TokenRefreshCache(defaultAzureCredential, trc); diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/HandleReauthentication.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/HandleReauthentication.java index 0fd7abcf527bd..7883dedb0adc7 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/HandleReauthentication.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/HandleReauthentication.java @@ -26,7 +26,7 @@ public static void main(String[] args) { // Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password. // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. - TokenRequestContext trc = new TokenRequestContext().addScopes("https://redis.azure.com/.default"); + TokenRequestContext trc = new TokenRequestContext().addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); AccessToken accessToken = getAccessToken(defaultAzureCredential, trc); // Host Name, Port, Username, and Microsoft Entra token are required here. diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/HellloWorld.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/HellloWorld.java index b7f46ce3340bf..61f9073f82210 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/HellloWorld.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/HellloWorld.java @@ -27,7 +27,7 @@ public static void main(String[] args) { // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. String token = defaultAzureCredential .getToken(new TokenRequestContext() - .addScopes("https://redis.azure.com/.default")).block().getToken(); + .addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default")).block().getToken(); // Build Redis URI with host and authentication details. // TODO: Replace Host Name with Azure Cache for Redis Host Name. diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/withcredentialprovider/AuthenticateWithTokenCache.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/withcredentialprovider/AuthenticateWithTokenCache.java index cfff5ea52d67e..2a4a679ff4d05 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/withcredentialprovider/AuthenticateWithTokenCache.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/withcredentialprovider/AuthenticateWithTokenCache.java @@ -112,7 +112,7 @@ private static RedisClient createLettuceRedisClient(String hostName, int port, R */ public static class AzureRedisCredentials implements RedisCredentials { private TokenRequestContext tokenRequestContext = new TokenRequestContext() - .addScopes("https://redis.azure.com/.default"); + .addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); private TokenCredential tokenCredential; private TokenRefreshCache refreshCache; private final String username; diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/withcredentialprovider/HandleReauthentication.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/withcredentialprovider/HandleReauthentication.java index 1893059e2c142..472979906f2b4 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/withcredentialprovider/HandleReauthentication.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/withcredentialprovider/HandleReauthentication.java @@ -89,7 +89,7 @@ private static RedisClient createLettuceRedisClient(String hostName, int port, S */ public static class AzureRedisCredentials implements RedisCredentials { private TokenRequestContext tokenRequestContext = new TokenRequestContext() - .addScopes("https://redis.azure.com/.default"); + .addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); private TokenCredential tokenCredential; private final String username; diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/withcredentialprovider/HelloWorld.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/withcredentialprovider/HelloWorld.java index 6c5ba714d8dbf..2f80c69d78714 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/withcredentialprovider/HelloWorld.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Lettuce/java/com/azure/lettuce/sample/withcredentialprovider/HelloWorld.java @@ -62,7 +62,7 @@ public static void main(String[] args) { public static class AzureRedisCredentials implements RedisCredentials { // Note: The Scopes value will change as the Microsoft Entra authentication support hits public preview and eventually GA's. private TokenRequestContext tokenRequestContext = new TokenRequestContext() - .addScopes("https://redis.azure.com/.default"); + .addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); private TokenCredential tokenCredential; private final String username; diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/Azure-AAD-Authentication-With-Redisson.md b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/Azure-AAD-Authentication-With-Redisson.md index f4dbc4a1bacee..468a88f183a5a 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/Azure-AAD-Authentication-With-Redisson.md +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/Azure-AAD-Authentication-With-Redisson.md @@ -16,13 +16,13 @@ com.azure azure-identity - 1.11.2 + 1.8.2 org.redisson redisson - 3.27.0 + 3.20.1 ``` @@ -51,7 +51,7 @@ DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilde // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. String token = defaultAzureCredential .getToken(new TokenRequestContext() - .addScopes("https://redis.azure.com/.default")).block().getToken(); + .addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default")).block().getToken(); // Create Client Configuration Config config = new Config(); @@ -99,7 +99,7 @@ DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilde // Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password. // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. -TokenRequestContext trc = new TokenRequestContext().addScopes("https://redis.azure.com/.default"); +TokenRequestContext trc = new TokenRequestContext().addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); AccessToken accessToken = getAccessToken(defaultAzureCredential, trc); // Create Redisson Client @@ -171,7 +171,7 @@ DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilde // Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password. // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. -TokenRequestContext trc = new TokenRequestContext().addScopes("https://redis.azure.com/.default"); +TokenRequestContext trc = new TokenRequestContext().addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); // Instantiate the Token Refresh Cache, this cache will proactively refresh the access token 2 - 5 minutes before expiry. TokenRefreshCache tokenRefreshCache = new TokenRefreshCache(defaultAzureCredential, trc); @@ -288,7 +288,7 @@ public static class TokenRefreshCache { In this error scenario, the username provided and the access token used as password are not compatible. To mitigate this error, navigate to your Azure Cache for Redis resource in the Azure portal. Confirm that: * In **Data Access Configuration**, you've assigned the required role to your user/service principal identity. -* Under **Authentication** -> **Microsoft Entra Authentication** category the **Enable Microsoft Entra Authentication** box is selected. If not, select it and select the **Save** button. +* In **Advanced settings**, the **Microsoft Entra Authentication** box is selected. If not, select it and select the **Save** button. ##### Permissions not granted / NOPERM Error In this error scenario, the authentication was successful, but your registered user/service principal is not granted the RBAC permission to perform the action. diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/java/com/azure/redisson/sample/AuthenticateWithTokenCache.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/java/com/azure/redisson/sample/AuthenticateWithTokenCache.java index 62c45bb54d45a..aea4c96f6a824 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/java/com/azure/redisson/sample/AuthenticateWithTokenCache.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/java/com/azure/redisson/sample/AuthenticateWithTokenCache.java @@ -30,7 +30,7 @@ public static void main(String[] args) { // Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password. // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. - TokenRequestContext trc = new TokenRequestContext().addScopes("https://redis.azure.com/.default"); + TokenRequestContext trc = new TokenRequestContext().addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); // Instantiate the Token Refresh Cache, this cache will proactively refresh the access token 2 - 5 minutes before expiry. TokenRefreshCache tokenRefreshCache = new TokenRefreshCache(defaultAzureCredential, trc); diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/java/com/azure/redisson/sample/HandleReauthentication.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/java/com/azure/redisson/sample/HandleReauthentication.java index 197e78e45e0e3..46c103631d219 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/java/com/azure/redisson/sample/HandleReauthentication.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/java/com/azure/redisson/sample/HandleReauthentication.java @@ -24,7 +24,7 @@ public static void main(String[] args) { // Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password. // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. - TokenRequestContext trc = new TokenRequestContext().addScopes("https://redis.azure.com/.default"); + TokenRequestContext trc = new TokenRequestContext().addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default"); AccessToken accessToken = getAccessToken(defaultAzureCredential, trc); // Create Redisson Client diff --git a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/java/com/azure/redisson/sample/HelloWorld.java b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/java/com/azure/redisson/sample/HelloWorld.java index 4084ac43fe946..35ec74ebbc7e5 100644 --- a/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/java/com/azure/redisson/sample/HelloWorld.java +++ b/sdk/identity/azure-identity/src/samples/Azure-Cache-For-Redis/Redisson/java/com/azure/redisson/sample/HelloWorld.java @@ -23,7 +23,7 @@ public static void main(String[] args) { // Note: The Scopes parameter will change as the Microsoft Entra authentication support hits public preview and eventually GA's. String token = defaultAzureCredential .getToken(new TokenRequestContext() - .addScopes("https://redis.azure.com/.default")).block().getToken(); + .addScopes("acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default")).block().getToken(); // Create Client Configuration Config config = new Config(); diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/DefaultAzureCredentialTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/DefaultAzureCredentialTest.java index 9cc3389f9453c..e7c7cd5619e42 100644 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/DefaultAzureCredentialTest.java +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/DefaultAzureCredentialTest.java @@ -3,7 +3,6 @@ package com.azure.identity; -import com.azure.core.credential.AccessToken; import com.azure.core.credential.TokenRequestContext; import com.azure.core.exception.ClientAuthenticationException; import com.azure.core.test.utils.TestConfigurationSource; @@ -410,87 +409,4 @@ public void testValidMultiTenantAuth() { StepVerifier.create(credential.getToken(request)) .verifyErrorMatches(e -> e.getCause() instanceof MsalServiceException); } - - @Test - public void testCredentialCaching() { - // setup - String token1 = "token1"; - TokenRequestContext request = new TokenRequestContext().addScopes("https://management.azure.com"); - OffsetDateTime expiresAt = OffsetDateTime.now(ZoneOffset.UTC).plusHours(1); - EmptyEnvironmentConfigurationSource source = new EmptyEnvironmentConfigurationSource(); - Configuration configuration = new ConfigurationBuilder(source, source, source).build(); - - try (MockedConstruction managedIdentityCredentialMock = mockConstruction(ManagedIdentityCredential.class, (managedIdentityCredential, context) -> { - when(managedIdentityCredential.getToken(request)) - .thenReturn(Mono.error(new CredentialUnavailableException("Cannot get token from Managed Identity credential"))) - .thenReturn(Mono.error(new RuntimeException("Second call should not be made"))); - }); MockedConstruction intelliJCredentialMock = mockConstruction(IntelliJCredential.class, (intelliJCredential, context) -> { - when(intelliJCredential.getToken(request)) - .thenReturn(Mono.error(new CredentialUnavailableException("Cannot get token from InteliJ credential"))) - .thenReturn(Mono.error(new RuntimeException("Second call should not be made"))); - }); MockedConstruction powerShellCredentialMock = mockConstruction(AzurePowerShellCredential.class, (powerShellCredential, context) -> { - when(powerShellCredential.getToken(request)) - .thenReturn(Mono.error(new CredentialUnavailableException("Cannot get token from PowerShell credential"))) - .thenReturn(Mono.error(new RuntimeException("Second call should not be made"))); - }); MockedConstruction azureCliCredentialMock = mockConstruction(AzureCliCredential.class, (azureCliCredential, context) -> { - when(azureCliCredential.getToken(request)) - .thenReturn(Mono.error(new CredentialUnavailableException("Cannot get token from Azure CLI credential"))) - .thenReturn(Mono.error(new RuntimeException("Second call should not be made"))); - }); MockedConstruction azureDeveloperCliCredentialMock = mockConstruction(AzureDeveloperCliCredential.class, (azureDeveloperCliCredential, context) -> { - when(azureDeveloperCliCredential.getToken(request)).thenReturn(TestUtils.getMockAccessToken(token1, expiresAt)); - })) { - - // test - DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().configuration(configuration).build(); - StepVerifier.create(credential.getToken(request)).expectNextMatches(accessToken -> token1.equals(accessToken.getToken()) && expiresAt.getSecond() == accessToken.getExpiresAt().getSecond()).verifyComplete(); - - // Second call should return token from cached credential. - StepVerifier.create(credential.getToken(request)).expectNextMatches(accessToken -> token1.equals(accessToken.getToken()) && expiresAt.getSecond() == accessToken.getExpiresAt().getSecond()).verifyComplete(); - - Assertions.assertNotNull(managedIdentityCredentialMock); - Assertions.assertNotNull(intelliJCredentialMock); - Assertions.assertNotNull(powerShellCredentialMock); - Assertions.assertNotNull(azureCliCredentialMock); - Assertions.assertNotNull(azureDeveloperCliCredentialMock); - } - } - - @Test - public void testCredentialCachingSync() { - // setup - String token1 = "token1"; - TokenRequestContext request = new TokenRequestContext().addScopes("https://management.azure.com"); - OffsetDateTime expiresAt = OffsetDateTime.now(ZoneOffset.UTC).plusHours(1); - - RuntimeException runtimeException = new RuntimeException("Second call should not be made"); - - try (MockedConstruction managedIdentityCredentialMock = mockConstruction(ManagedIdentityCredential.class, (managedIdentityCredential, context) -> { - when(managedIdentityCredential.getTokenSync(request)).thenThrow(new CredentialUnavailableException("Cannot get token from Managed Identity credential")).thenThrow(runtimeException); - }); MockedConstruction intelliJCredentialMock = mockConstruction(IntelliJCredential.class, (intelliJCredential, context) -> { - when(intelliJCredential.getTokenSync(request)).thenThrow(new CredentialUnavailableException("Cannot get token from IntelliJ Credential")).thenThrow(runtimeException); - }); MockedConstruction powerShellCredentialMock = mockConstruction(AzurePowerShellCredential.class, (powerShellCredential, context) -> { - when(powerShellCredential.getTokenSync(request)).thenThrow(new CredentialUnavailableException("Cannot get token from Powershell credential")).thenThrow(runtimeException); - }); MockedConstruction azureCliCredentialMock = mockConstruction(AzureCliCredential.class, (azureCliCredential, context) -> { - when(azureCliCredential.getTokenSync(request)).thenThrow(new CredentialUnavailableException("Cannot get token from Cli credential")).thenThrow(runtimeException); - }); MockedConstruction azureDeveloperCliCredentialMock = mockConstruction(AzureDeveloperCliCredential.class, (azureDeveloperCliCredential, context) -> { - when(azureDeveloperCliCredential.getTokenSync(request)).thenReturn(TestUtils.getMockAccessTokenSync(token1, expiresAt)); - })) { - // test - DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build(); - AccessToken accessToken1 = credential.getTokenSync(request); - Assertions.assertEquals(token1, accessToken1.getToken()); - Assertions.assertEquals(expiresAt.getSecond(), accessToken1.getExpiresAt().getSecond()); - - // Second call should return token from cached credential. - AccessToken accessToken2 = credential.getTokenSync(request); - Assertions.assertEquals(token1, accessToken2.getToken()); - Assertions.assertEquals(expiresAt.getSecond(), accessToken2.getExpiresAt().getSecond()); - - Assertions.assertNotNull(managedIdentityCredentialMock); - Assertions.assertNotNull(intelliJCredentialMock); - Assertions.assertNotNull(powerShellCredentialMock); - Assertions.assertNotNull(azureCliCredentialMock); - Assertions.assertNotNull(azureDeveloperCliCredentialMock); - } - } } diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientOptionsTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientOptionsTest.java index 7e1b47abcbc57..60f6b7bf734f6 100644 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientOptionsTest.java +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientOptionsTest.java @@ -42,13 +42,4 @@ public void testDisableAuthorityValidationAndInstanceDiscovery() { identityClientOptions.disableInstanceDiscovery(); Assertions.assertFalse(identityClientOptions.isInstanceDiscoveryEnabled()); } - - @Test - public void testCloneDoesNotEnableThingsItShouldNot() { - IdentityClientOptions identityClientOptions = new IdentityClientOptions(); - - IdentityClientOptions clonedOptions = identityClientOptions.clone(); - Assertions.assertFalse(clonedOptions.isBrokerEnabled()); - Assertions.assertFalse(clonedOptions.isUnsafeSupportLoggingEnabled()); - } } diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientTests.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientTests.java index 1c0d2ebc2be09..9ff84f6ed7ee3 100644 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientTests.java +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientTests.java @@ -23,6 +23,7 @@ import com.microsoft.aad.msal4j.PublicClientApplication; import com.microsoft.aad.msal4j.SilentParameters; import com.microsoft.aad.msal4j.UserNamePasswordParameters; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.AdditionalMatchers; @@ -49,9 +50,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.anyBoolean; @@ -90,6 +89,8 @@ public void testValidSecret() { }) .verifyComplete(); }); + + } @Test diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/models/AzureCliTokenTests.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/models/AzureCliTokenTests.java deleted file mode 100644 index bc84fbcc467c1..0000000000000 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/models/AzureCliTokenTests.java +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.implementation.models; - -import com.azure.json.JsonProviders; -import com.azure.json.JsonReader; -import com.azure.json.JsonWriter; -import org.junit.jupiter.api.Test; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.time.Clock; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.OffsetDateTime; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -public class AzureCliTokenTests { - - String jsonWithExpiresOnUnixTime = "{\n" - + " \"accessToken\": \"tokenValue\",\n" - + " \"expiresOn\": \"2024-02-28 12:05:53.000000\",\n" - + " \"expires_on\": 1709150753,\n" - + " \"subscription\": \"subscriptionValue\",\n" - + " \"tenant\": \"tenantValue\",\n" - + " \"tokenType\": \"Bearer\"\n" - + "}"; - - // This is the payload that gets parsed in the fallback case. It does not have time zone information. - // For test purposes, we need to inject the current time here, so the test works in different regions. - String jsonWithoutExpiresOnUnixTime = "{\n" - + " \"accessToken\": \"tokenValue\",\n" - + " \"expiresOn\": \"%s\",\n" - + " \"subscription\": \"subscriptionValue\",\n" - + " \"tenant\": \"tenantValue\",\n" - + " \"tokenType\": \"Bearer\"\n" - + "}"; - @Test - public void testRoundTripWithoutExpiresOnUnixTime() { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - // This test is largely testing the round trip and conversion of the local time returned from az - // to a UTC time. Set up the current time to allow this to work in all time zones. - Clock clock = Clock.fixed(Instant.parse("2024-02-28T20:05:53.123456Z"), ZoneId.of("Z")); - OffsetDateTime expected = OffsetDateTime.now(clock); - LocalDateTime localNow = expected.atZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime(); - expected = expected.atZoneSameInstant(ZoneId.of("Z")).toOffsetDateTime(); - // recreate the incorrect date format from az - String nowString = localNow.format(DateTimeFormatter.ISO_DATE) + " " + localNow.format(DateTimeFormatter.ISO_TIME); - String localJson = String.format(jsonWithoutExpiresOnUnixTime, nowString); - - try { - try (JsonReader reader = JsonProviders.createReader(localJson)) { - AzureCliToken token = AzureCliToken.fromJson(reader); - JsonWriter writer = JsonProviders.createWriter(stream); - token.toJson(writer); - assertNull(token.getExpiresOnUnixTime()); - assertEquals("tokenValue", token.getAccessToken()); - assertEquals(nowString, token.getExpiresOn()); - assertEquals("subscriptionValue", token.getSubscription()); - assertEquals("tenantValue", token.getTenant()); - assertEquals("Bearer", token.getTokenType()); - assertEquals(expected, token.getTokenExpiration()); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Test - public void testRoundTripWithExpiresOnUnixTime() { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - - try { - try (JsonReader reader = JsonProviders.createReader(jsonWithExpiresOnUnixTime)) { - AzureCliToken token = AzureCliToken.fromJson(reader); - JsonWriter writer = JsonProviders.createWriter(stream); - token.toJson(writer); - assertEquals("tokenValue", token.getAccessToken()); - assertEquals("2024-02-28 12:05:53.000000", token.getExpiresOn()); - assertEquals(1709150753, token.getExpiresOnUnixTime()); - assertEquals("subscriptionValue", token.getSubscription()); - assertEquals("tenantValue", token.getTenant()); - assertEquals("Bearer", token.getTokenType()); - // this test works fine with the hardcoded values since we don't care about the conversion through - // local time. - assertEquals(OffsetDateTime.parse("2024-02-28T20:05:53Z"), token.getTokenExpiration()); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - // This test validates the json parsing works both ways. - @Test - public void testDoubleRoundTrip() { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - - try (JsonReader reader = JsonProviders.createReader(jsonWithExpiresOnUnixTime)) { - AzureCliToken token = AzureCliToken.fromJson(reader); - JsonWriter writer = JsonProviders.createWriter(stream); - token.toJson(writer); - writer.close(); - - try (JsonReader reader2 = JsonProviders.createReader(stream.toByteArray())) { - AzureCliToken token2 = AzureCliToken.fromJson(reader2); - assertEquals("tokenValue", token2.getAccessToken()); - assertEquals("2024-02-28 12:05:53.000000", token2.getExpiresOn()); - assertEquals(1709150753, token2.getExpiresOnUnixTime()); - assertEquals("subscriptionValue", token2.getSubscription()); - assertEquals("tenantValue", token2.getTenant()); - assertEquals("Bearer", token2.getTokenType()); - assertEquals(OffsetDateTime.parse("2024-02-28T20:05:53Z"), token2.getTokenExpiration()); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } -} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/recorded/ClientAssertionCredentialTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/recorded/ClientAssertionCredentialTest.java deleted file mode 100644 index de496bce679be..0000000000000 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/recorded/ClientAssertionCredentialTest.java +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.recorded; - -import com.azure.core.credential.AccessToken; -import com.azure.core.credential.TokenRequestContext; -import com.azure.core.http.HttpClient; -import com.azure.identity.ClientAssertionCredential; -import com.azure.identity.ClientAssertionCredentialBuilder; -import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import reactor.test.StepVerifier; - - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -public class ClientAssertionCredentialTest extends IdentityTestBase { - - private static final String DISPLAY_NAME_WITH_ARGUMENTS = "{displayName} with [{arguments}]"; - private ClientAssertionCredential credential; - - private void initializeClient(HttpClient httpClient) { - credential = new ClientAssertionCredentialBuilder() - .clientId(isPlaybackMode() ? "Dummy-Id" : getClientId()) - .tenantId(isPlaybackMode() ? "Dummy-Id" : getTenantId()) - .clientAssertion(() -> isPlaybackMode() ? INVALID_DUMMY_CLIENT_ASSERTION : getClientAssertion()) - .pipeline(super.getHttpPipeline(httpClient)) - .build(); - } - - @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) - @MethodSource("getHttpClients") - @EnabledIfEnvironmentVariable(named = "AZURE_TEST_MODE", matches = "PLAYBACK") - public void getToken(HttpClient httpClient) { - // arrange - initializeClient(httpClient); - - // act - AccessToken actual = credential.getTokenSync(new TokenRequestContext().addScopes("https://vault.azure.net/.default")); - - // assert - assertNotNull(actual); - assertNotNull(actual.getToken()); - assertNotNull(actual.getExpiresAt()); - } - - @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) - @MethodSource("getHttpClients") - @EnabledIfEnvironmentVariable(named = "AZURE_TEST_MODE", matches = "PLAYBACK") - public void getTokenAsync(HttpClient httpClient) { - // arrange - initializeClient(httpClient); - StepVerifier.create(credential.getToken(new TokenRequestContext().addScopes("https://vault.azure.net/.default"))) - .expectNextMatches(accessToken -> accessToken.getToken() != null && accessToken.getExpiresAt() != null) - .verifyComplete(); - } -} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/recorded/ClientCertificateCredentialTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/recorded/ClientCertificateCredentialTest.java deleted file mode 100644 index 6130c970f5fff..0000000000000 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/recorded/ClientCertificateCredentialTest.java +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.recorded; - -import com.azure.core.credential.AccessToken; -import com.azure.core.credential.TokenRequestContext; -import com.azure.core.http.HttpClient; -import com.azure.core.util.Configuration; -import com.azure.identity.ClientCertificateCredential; -import com.azure.identity.ClientCertificateCredentialBuilder; -import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import reactor.test.StepVerifier; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -public class ClientCertificateCredentialTest extends IdentityTestBase { - - private static final String DISPLAY_NAME_WITH_ARGUMENTS = "{displayName} with [{arguments}]"; - private ClientCertificateCredential credential; - - private void initializeClient(HttpClient httpClient) { - ClientCertificateCredentialBuilder builder = new ClientCertificateCredentialBuilder() - .clientId(isPlaybackMode() ? "Dummy-Id" : getClientId()) - .tenantId(isPlaybackMode() ? "Dummy-Id" : getTenantId()) - .pipeline(super.getHttpPipeline(httpClient)); - - credential = isPlaybackMode() - ? builder.pemCertificate(getClass().getClassLoader().getResourceAsStream("pemCert.pem")).build() - : builder.pemCertificate(Configuration.getGlobalConfiguration().get("AZURE_CLIENT_CERTIFICATE_PATH")).build(); - } - - @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) - @MethodSource("getHttpClients") - @EnabledIfEnvironmentVariable(named = "AZURE_TEST_MODE", matches = "PLAYBACK") - public void getToken(HttpClient httpClient) { - // arrange - initializeClient(httpClient); - - // act - AccessToken actual = credential.getTokenSync(new TokenRequestContext().addScopes("https://vault.azure.net/.default")); - - // assert - assertNotNull(actual); - assertNotNull(actual.getToken()); - assertNotNull(actual.getExpiresAt()); - } - - @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) - @MethodSource("getHttpClients") - @EnabledIfEnvironmentVariable(named = "AZURE_TEST_MODE", matches = "PLAYBACK") - public void getTokenAsync(HttpClient httpClient) { - // arrange - initializeClient(httpClient); - StepVerifier.create(credential.getToken(new TokenRequestContext().addScopes("https://vault.azure.net/.default"))) - .expectNextMatches(accessToken -> accessToken.getToken() != null && accessToken.getExpiresAt() != null) - .verifyComplete(); - } -} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/recorded/ClientSecretCredentialTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/recorded/ClientSecretCredentialTest.java deleted file mode 100644 index 58966625e6d78..0000000000000 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/recorded/ClientSecretCredentialTest.java +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.recorded; - -import com.azure.core.credential.AccessToken; -import com.azure.core.credential.TokenRequestContext; -import com.azure.core.http.HttpClient; -import com.azure.identity.ClientSecretCredential; -import com.azure.identity.ClientSecretCredentialBuilder; -import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import reactor.test.StepVerifier; - - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -public class ClientSecretCredentialTest extends IdentityTestBase { - - private static final String DISPLAY_NAME_WITH_ARGUMENTS = "{displayName} with [{arguments}]"; - private ClientSecretCredential credential; - - private void initializeClient(HttpClient httpClient) { - credential = new ClientSecretCredentialBuilder() - .clientId(isPlaybackMode() ? "Dummy-Id" : getClientId()) - .tenantId(isPlaybackMode() ? "Dummy-Id" : getTenantId()) - .clientSecret(isPlaybackMode() ? "Dummy-Secret" : getClientSecret()) - .pipeline(super.getHttpPipeline(httpClient)) - .build(); - } - - @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) - @MethodSource("getHttpClients") - @EnabledIfEnvironmentVariable(named = "AZURE_TEST_MODE", matches = "PLAYBACK") - public void getToken(HttpClient httpClient) { - // arrange - initializeClient(httpClient); - - // act - AccessToken actual = credential.getTokenSync(new TokenRequestContext().addScopes("https://vault.azure.net/.default")); - - // assert - assertNotNull(actual); - assertNotNull(actual.getToken()); - assertNotNull(actual.getExpiresAt()); - } - - @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) - @MethodSource("getHttpClients") - @EnabledIfEnvironmentVariable(named = "AZURE_TEST_MODE", matches = "PLAYBACK") - public void getTokenAsync(HttpClient httpClient) { - // arrange - initializeClient(httpClient); - StepVerifier.create(credential.getToken(new TokenRequestContext().addScopes("https://vault.azure.net/.default"))) - .expectNextMatches(accessToken -> accessToken.getToken() != null && accessToken.getExpiresAt() != null) - .verifyComplete(); - } -} diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/recorded/IdentityTestBase.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/recorded/IdentityTestBase.java deleted file mode 100644 index 813865bdf472a..0000000000000 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/recorded/IdentityTestBase.java +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.identity.recorded; - -import com.azure.core.http.HttpClient; -import com.azure.core.http.HttpPipeline; -import com.azure.core.http.HttpPipelineBuilder; -import com.azure.core.http.policy.HttpPipelinePolicy; -import com.azure.core.test.TestProxyTestBase; -import com.azure.core.test.models.*; -import com.azure.core.util.Configuration; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class IdentityTestBase extends TestProxyTestBase { - - public static final String INVALID_DUMMY_TOKEN = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJlbWFpbCI6IkJvYkBjb250b" - + "3NvLmNvbSIsImdpdmVuX25hbWUiOiJCb2IiLCJpc3MiOiJodHRwOi8vRGVmYXVsdC5Jc3N1ZXIuY29tIiwiYXVkIjoiaHR0cDovL0RlZm" - + "F1bHQuQXVkaWVuY2UuY29tIiwiaWF0IjoiMTYwNzk3ODY4MyIsIm5iZiI6IjE2MDc5Nzg2ODMiLCJleHAiOiIxNjA3OTc4OTgzIn0."; - - public static final String INVALID_DUMMY_CLIENT_ASSERTION = "eyJ4NXQiOiJOVmhMQWFmMVVRQTdpZVpKTk5SWmhKWmhKV3c9Iiwi" - + "YWxnIjoiUlMyNTYifQ.eyJpc3MiOiIwNmM4MmFjZC1hMDIzLTQwMGQtYjZhOC1kNjU3MDQ5NzliNGYiLCJhdWQiOiJodHRwczovL2xvZ2l" - + "uLm1pY3Jvc29mdG9ubGluZS5jb20vNDZkZDVhNDMtZDE5YS00YWU0LTljNjAtNjUwY2M4OTA5YjExL29hdXRoMi92Mi4wL3Rva2VuIiwic" - + "3ViIjoiMDZjODJhY2QtYTAyMy00MDBkLWI2YTgtZDY1NzA0OTc5YjRmIiwibmJmIjoxNzA4NjUyNjQyLCJleHAiOjE3MDg2NTMyNDIsImp" - + "0aSI6ImQ4YTVlZThlLWZmNzMtNDdmZC05NTg0LTFiZmI3NTc3NDc2MiJ9.EKjPiv89K7_awBtOSrguQ9BUIbO_RylvyPuH8a6u-N-6FdX3" - + "dG3V9fEnR7PEId8yZnQq4QAGyFirmf9vPy8XXdJ1h-Ok8PzFcU-FtN-aFddRhDBZEj37kXtqyNqEq-lw4eQvuURCQrk_e8ZsG6XR2SZsyTM" - + "uBfr_maQi0Uagg-yax9_ITK1OmJhfv0e93H4zBNsCucT-LFT2IyvXaULBoq04HyhFkhlvlyC8pSiM9jqTYwm64y0ipG-LHbq1jmwHdyTAXx" - + "OtYfPjXZTAHZD2NakTZQjf3-TC-Ol-7xuD5rtj749RApstk3YglQ5L2rf1e989nu7Jvuh8-XLkz_wrIe06RaBeZsztS-yg3ZlrfOB34glq7" - + "YpjRAYQXcnnHzfLLibxmMVY0bL1nLRR1PXmgBX2udxpHdm49CwaEXzO4RXPCKMwndFktkxNCv8yXUI1lhZWesVXmVns4RnGF_3HI8J3peS-" - + "JQ6b3ZYgekD12tJ54GxaebjXXepQz9AHyfRVPJjayT4YBb7V4Gtq1qZhNi44BFx0f-gaZdkBQhx2eaMRxFjJ9lqPTEYWHO0G2gcfH6MIL7r" - + "EwMfQ30ZjDYuVfiiAe7FE8L1ANxWsXvmNwYrRC7U_QCHXl7nwnflVb_1Isd-T2E-bc6z3jFbLyLlE4SYzP6468GlhlCwajIybEME"; - - HttpPipeline getHttpPipeline(HttpClient httpClient) { - - final List policies = new ArrayList<>(); - - if (interceptorManager.isRecordMode() || interceptorManager.isPlaybackMode()) { - List customSanitizers = new ArrayList<>(); - customSanitizers.add(new TestProxySanitizer("$..access_token", null, INVALID_DUMMY_TOKEN, - TestProxySanitizerType.BODY_KEY)); - customSanitizers.add(new TestProxySanitizer("client-request-id", null, "REDACTED", - TestProxySanitizerType.HEADER)); - customSanitizers.add(new TestProxySanitizer("x-client-last-telemetry", null, "REDACTED", - TestProxySanitizerType.HEADER)); - customSanitizers.add(new TestProxySanitizer(null, "(client_id=)[^&]+", "$1Dummy-Id", - TestProxySanitizerType.BODY_REGEX)); - customSanitizers.add(new TestProxySanitizer(null, "(client_secret=)[^&]+", "$1Dummy-Secret", - TestProxySanitizerType.BODY_REGEX)); - customSanitizers.add(new TestProxySanitizer(null, "(client_assertion=)[^&]+", "$1Dummy-Secret", - TestProxySanitizerType.BODY_REGEX)); - - interceptorManager.addSanitizers(customSanitizers); - } - - if (interceptorManager.isRecordMode()) { - policies.add(interceptorManager.getRecordPolicy()); - } - - if (interceptorManager.isPlaybackMode()) { - List customMatchers = new ArrayList<>(); - customMatchers.add(new BodilessMatcher()); - customMatchers.add(new CustomMatcher().setExcludedHeaders(Collections.singletonList("X-MRC-CV"))); - interceptorManager.addMatchers(customMatchers); - } - - HttpPipeline pipeline = new HttpPipelineBuilder() - .policies(policies.toArray(new HttpPipelinePolicy[0])) - .httpClient(interceptorManager.isPlaybackMode() ? interceptorManager.getPlaybackClient() : httpClient) - .build(); - - return pipeline; - } - - String getClientId() { - return Configuration.getGlobalConfiguration().get("AZURE_CLIENT_ID"); - } - - String getTenantId() { - return Configuration.getGlobalConfiguration().get("AZURE_TENANT_ID"); - } - - String getClientSecret() { - return Configuration.getGlobalConfiguration().get("AZURE_CLIENT_SECRET"); - } - - String getClientAssertion() { - return Configuration.getGlobalConfiguration().get("AZURE_CLIENT_ASSERTION"); - } - - boolean isPlaybackMode() { - return interceptorManager.isPlaybackMode(); - } -} diff --git a/sdk/identity/azure-identity/src/test/resources/pemCert.pem b/sdk/identity/azure-identity/src/test/resources/pemCert.pem deleted file mode 100644 index 6eff096e168da..0000000000000 --- a/sdk/identity/azure-identity/src/test/resources/pemCert.pem +++ /dev/null @@ -1,83 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIJALbGj/XdaqzxMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQwHhcNMTkwNjE5MjAyNzM5WhcNMjAwNjE4MjAyNzM5WjBF -MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 -ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAoavpJHmWlai03e9+dtflcjKMaqRhFSplhmzAxi+DoQi6Yx+yzQ+X/hlM -MpSIfZU0gxXncNpp2wj2YL0vt8BjV2Ii1KUaZ50PLgBrn2AkWchUf4wnSyIle5gu -1X3AelB6pqHc1q4/t49096NecGlagJlcP5uJwT02LnZDF+dRknGypZmxE0EUvRPF -AE5z+5hWNeQSEXTejU23OpxkD5hcwV9Zh+fJZL6z9ifzvRMTDLdKdPqZqfA1pWt5 -yHC4ZLXMCuRNxRd/rYj9cC/mgz6TJ0F1MHt4VSLIiOaZiAF1OhDg5STK052biHIG -4DORTHsU+1UgStOCXDYCBzhv4fa/Vht/Y8I4dC2crEHFKP80Cv49gyQc1GME2AUb -aNbvt6nlVM6KkoTN1MaJMmqEYQJ7P0b6sAaQq6eqx5TZ3Hy3QjaFFh4NDTTuqlhy -jmEyWWWS0bFxr7NoLWOn3v32mDJoAIFk/elnVq8rS5Q2Yhjun+hZprMwgBo5XsA+ -hVnagY3BJ3re/xNey/k9s9G5KB0FR81repLqRGL3fIj5BdF94K/Ai9mk/vCIUlTH -UyQrFsV1FHdWqgA60q6hKqY4FazSQ5Vo93FRubWZOBdJnsw6rZtwNXdQeIS+QBsf -fMRdm69yyRPEgpgiK3pnbZN75/nbdjT3VqF3J/5eoRMwcK16zOMCAwEAAaNTMFEw -HQYDVR0OBBYEFKPqOiR8Fd0zCWMQea85Ywfayw3HMB8GA1UdIwQYMBaAFKPqOiR8 -Fd0zCWMQea85Ywfayw3HMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD -ggIBAEjPNpPnNu+qJ2akDCiMmzimo7awXQ9JinYRr3aVDuJ6mqAkmzM1opp/JvHb -Jba9RsLOhUoN9f7JAZt0XxgsZECMzE69RyOnZ4BNY6Bd4PFJ2DX1Hajp6MhGhRUO -c+jPf6jPmfUSD0by0buWvrTASJUJ4xKqhVqCWlMkvAnMe4zX3U2VFDXYl2wgtHOv -kHQIGE8+pCYwC0O+yeuxwaNvNNdyZxaL3qRbRbTbx7nIKKnj1bnVePxIw+ilpZEb -kNZLS+sIyhc+o95comx0EZdFat5JdJyfMlYrBnLyD8fn5QFGxwhdd1o2HGZt23rQ -z+uZF6BCwzNigNgVelB/oWr6lVdhmRG6hinzw2QTaSoZQ5ax+J6keJQTAyZNvc/0 -r7XEaULfhrAuCUoNTQRE7pG3qnIHxCnyHSC8soDFiE8PoIVBkf/4An5ysNvq78Wc -lKQGmBpxpXJ37g76TnIFhYnwhtB372iMmuweLXFfUTX/vgbDG9tUfsQsJvibPhIX -thIZG7k3F3ZgbKFh9ykywHy/6eh77Wa0V8avqctX0FndrylsT31DoR/u2KZ2pYxi -aFoSbH6Wn173YNaqlhp/ZV47nrNo/gaNj4MU9pstpPkSaz3VWsu5PaWT+2uR/eLd -D0nDQrwvp98Fds2hiqq8bsKSghdrYYlcszmdauPsJhgbGgFl ------END CERTIFICATE----- ------BEGIN PRIVATE KEY----- -MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQChq+kkeZaVqLTd -73521+VyMoxqpGEVKmWGbMDGL4OhCLpjH7LND5f+GUwylIh9lTSDFedw2mnbCPZg -vS+3wGNXYiLUpRpnnQ8uAGufYCRZyFR/jCdLIiV7mC7VfcB6UHqmodzWrj+3j3T3 -o15waVqAmVw/m4nBPTYudkMX51GScbKlmbETQRS9E8UATnP7mFY15BIRdN6NTbc6 -nGQPmFzBX1mH58lkvrP2J/O9ExMMt0p0+pmp8DWla3nIcLhktcwK5E3FF3+tiP1w -L+aDPpMnQXUwe3hVIsiI5pmIAXU6EODlJMrTnZuIcgbgM5FMexT7VSBK04JcNgIH -OG/h9r9WG39jwjh0LZysQcUo/zQK/j2DJBzUYwTYBRto1u+3qeVUzoqShM3Uxoky -aoRhAns/RvqwBpCrp6rHlNncfLdCNoUWHg0NNO6qWHKOYTJZZZLRsXGvs2gtY6fe -/faYMmgAgWT96WdWrytLlDZiGO6f6FmmszCAGjlewD6FWdqBjcEnet7/E17L+T2z -0bkoHQVHzWt6kupEYvd8iPkF0X3gr8CL2aT+8IhSVMdTJCsWxXUUd1aqADrSrqEq -pjgVrNJDlWj3cVG5tZk4F0mezDqtm3A1d1B4hL5AGx98xF2br3LJE8SCmCIremdt -k3vn+dt2NPdWoXcn/l6hEzBwrXrM4wIDAQABAoICACwjJs9Sco4BNP+yNrBzWKzI -qBUlM2v32yfL4QU6S5FXNKuDJ+lb7H7uoSLd8jV22pM/E6R3vJaT58+ZVsGvwG9G -14N+X6sR8eb5LmigcswgKRF5TfDxLZKEhaS7ZCUAe7uqTQQ/Jh4TCDfjXhEKci7R -r6Gd8QnUkEo29zI7cMWuTLtxLiq3hdXo48uln3x8pmyoC1bAtVGWegOCVr77NbeF -NIgp+42JktANMDnaT0UVdTpigDko3zx+Dw1t2KmGCGKg2aqJM85IrAhIy4HhP4Nk -F35Y9w0nJeBaNGgxHbPwj7V/SfBkAuZJWx8ydOSQZbYIE3zaKajLBdq6ybDDEJEe -Y44nufPpzqH7yt+dabXx49Pxz8p5E+vObUh0NVfzSO/Nk32/uXoZKVx5vViBwCnX -N28pvi88vFoCU/FowGimJHPcxBGyWejgXWDMrYi0okBXYkO0gpHAFskV21EttF8c -eEQXlTfUjOTOFpQNaUJu+Azq/jjDEXG6TMPElN+pj2hBY/euVl6TNakXW8yomYuj -SkoGPioK4mw+ASok4o20hy7p4kLnmQuiM7gKsga/ppygIPrdor7OlSCCYxBUBoSS -qmsBioIAs7PQU/jcocyxIz6P0mfj3jGUcMf4sZEX5us6dvC4uf7e8gS9lpAunnBw -GNZLIiGd5sJPgy6PV0WBAoIBAQDSYttzXUAduxLnvCs5IDzIuAzFGaLs9nKBCwHf -sveCMFZ5aI0mPCHl5Js1qaceIqsisv4PKKEIwNotgZ6SupCd3ohKJ2ZlNyw7ivWf -3NcpWjSMrhtfm3clzH2Nyj8y3cnFU/QJmpIcHcHLXogSYrbGpqMRPzQFoGpzXrvZ -xKstb6GEns2ryR9X7zvHVeGH4TBMmpb7UgBFfEgq3tTtCf54WhYFeJl0cs840mOG -xFWGECteE74hwGGeFJEy+Uh4i1bsw74mSAu1+ewNj9ucsMwBwKX2IDI6ExZvX0pK -1N4gsarAF92L1XbgIskhUwJ30DRpBA+cW+jrsDF8nYahr6XTAoIBAQDEuToGSMBI -2SGzl2TJqf4A9Oy0PDFG63jiT1+tCd5sB5e8gSaTSohuPksLDHxv+7JP33DvB/3f -l5aLQjYQMTaCqFtU16bVgLt9mFA2Zdt8kK4s6TGtKffZWXJQAMAdvIJiOIVTj+GQ -3iFoTRcJC8UScKBZJ8kr+VJzeGVhvjYXTamp16vn7WX7nZ3p7KIIt/oEQD6G0rI3 -DrRj3NX6a32dfWsccORmONXguwrEAOsA0eB5gM3I4PA3PTsyEFjr1mWwKEMF79E1 -KtJrQKRUL7ixyA9uoaflvP+f7Vj4kVtiHO51+5Rl8ZjyKgiqUIh9FaEqpsfoUAD5 -uQVVItLjXIKxAoIBAQDP/Pdi5695NPaNrlM02I//ByVovd16UnIE7PLfSjiytkLn -J9tTD2ObuRNQS/ZxLmjtlvLf3ZTF6JJJJrmz6UkLKXKnjKgILDFIdCo77sGvmgQV -iBJ7xGBYN/9v65/rE6Rjtomt7OfBcBGkkkIHmxuC7D6N0GQHo/1ZLTCdK3bnJlMR -n0VJLT4VWudIO7kI8jEjqjjVIM4v45wc9cqexKCULstSgVWD7/S5AhVuqC68qMOW -8AGpsF1RQJgDQrrIoUhALYuQoO0i7H7XMX81OvuUR/ZKiq3dB/3IAPabYDJxM/PQ -kEdv9IrfLsSUc1IfTPBjWaZtN9ffGYLy5XCx68oNAoIBAC95pA8wL3dlL0TwHFqu -s6X3dchpXlsHKL00+pn/77WSf4P2hyC0tAgm8GVSNhWwYG/2NIL7IsF7C9G/wNxX -hBg0GRZ4lMKhtp2wzGrUWgvNvrsH6/0mS7Iga/3ysGp8u9qIWWS5LG6RrO5G7HA6 -buzsUUYy29HI8aT8QTs9dEBbdb6PVeU63YnDmACEIvaHr8am2nAfGPNAkTgoa1tr -5XzEb70FYZlpzfPWL9rtfclM3Sd1djQsVMx/8nE6kLsZmqDQlpwwLATwuKc5im7m -tWPyLAc+7A39dpNZ7EbQjYU4BjRi6oVPsOGAU2cG2GmXdrWcWlIuPI4HoMnTBaHp -CYECggEAVEYRkltT41NeHpGfQsbk9Juif5Z8OzryjeniApEmtplrvk/NLnEgZuXo -Qrdu1greDG7hZYf/EsUj+NmYvAmqcs6X+JF1O/ngHc2cVOMewUR/wRKRdzyTJOgq -kuGDkPfpm5BJdAZb+5rO+nrW8ljtA2PdRZWqWGaHBEIDrfqz53fxfEtPU+0+Z+Zz -0580pTXrHiFMixoDyrbDPmUQlg9ncE3MUpz2yj/x2C47LxhYgpMx73q6S7ibZ04q -VCIWDNNihXPOMVKBXY1eEzAJ3/UxhO5oZwNEedkBSC7nvjdaZZaAx/hFo3DPBT8w -GCW0/fPxstiXQaANvVLWIIih4VlLHg== ------END PRIVATE KEY-----