From cfb7f4cd80c9f292149f84b4349e245c176921fc Mon Sep 17 00:00:00 2001 From: "Yun Lu (MSFT)" <53427149+Luyunmt@users.noreply.github.com> Date: Tue, 23 Jun 2020 01:48:09 +0800 Subject: [PATCH] Simplify azure-identity error messaging (#9022) Co-authored-by: wantedfast --- .../identity/ChainedTokenCredential.java | 28 ++++++++++--------- .../azure/identity/EnvironmentCredential.java | 3 +- .../implementation/IdentityClient.java | 13 ++++++--- .../identity/AzureCliCredentialTest.java | 8 +++--- .../identity/DefaultAzureCredentialTest.java | 14 ++-------- 5 files changed, 32 insertions(+), 34 deletions(-) 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 88dbb58a1f93..043b67fd6d4f 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 @@ -7,13 +7,14 @@ import com.azure.core.credential.AccessToken; import com.azure.core.credential.TokenCredential; import com.azure.core.credential.TokenRequestContext; +import com.azure.core.exception.ClientAuthenticationException; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.ArrayList; import java.util.Deque; import java.util.List; -import java.util.stream.Collectors; /** * A token credential provider that can provide a credential from a list of providers. @@ -25,6 +26,8 @@ @Immutable public class ChainedTokenCredential implements TokenCredential { private final Deque credentials; + private final String unavailableError = this.getClass().getSimpleName() + " authentication failed. ---> "; + /** * Create an instance of chained token credential that aggregates a list of token @@ -38,27 +41,26 @@ public class ChainedTokenCredential implements TokenCredential { public Mono getToken(TokenRequestContext request) { List exceptions = new ArrayList<>(4); return Flux.fromIterable(credentials) - .flatMap(p -> p.getToken(request).onErrorResume(CredentialUnavailableException.class, t -> { - exceptions.add(t); + .flatMap(p -> p.getToken(request).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); return Mono.empty(); }), 1) .next() .switchIfEmpty(Mono.defer(() -> { - - StringBuilder message = new StringBuilder("Tried " - + credentials.stream().map(c -> c.getClass().getSimpleName()) - .collect(Collectors.joining(", ")) - + " but failed to acquire a token for any of them. Please verify the" - + " environment for the credentials" - + " and see more details in the causes below."); - // 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(), last); + last = new CredentialUnavailableException(current.getMessage() + "\r\n" + last.getMessage(), + last.getCause()); } - return Mono.error(new CredentialUnavailableException(message.toString(), last)); + return Mono.error(last); })); } } diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/EnvironmentCredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/EnvironmentCredential.java index c333e2118d9c..ab599c42e261 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/EnvironmentCredential.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/EnvironmentCredential.java @@ -77,7 +77,8 @@ public class EnvironmentCredential implements TokenCredential { public Mono getToken(TokenRequestContext request) { if (tokenCredential == null) { return Mono.error(logger.logExceptionAsError(new CredentialUnavailableException( - "Cannot create any credentials with the current environment variables"))); + "EnvironmentCredential authentication unavailable." + + " Environment variables are not fully configured."))); } else { return tokenCredential.getToken(request); } 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 649d7b8f3bc8..78da0dc1ddf2 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 @@ -347,7 +347,8 @@ public Mono authenticateWithAzureCli(TokenRequestContext request) { } if (line.startsWith(WINDOWS_PROCESS_ERROR_MESSAGE) || line.matches(LINUX_MAC_PROCESS_ERROR_MESSAGE)) { throw logger.logExceptionAsError( - new CredentialUnavailableException("Azure CLI not installed")); + new CredentialUnavailableException( + "AzureCliCredential authentication unavailable. Azure CLI not installed")); } output.append(line); } @@ -360,7 +361,9 @@ public Mono authenticateWithAzureCli(TokenRequestContext request) { String redactedOutput = redactInfo("\"accessToken\": \"(.*?)(\"|$)", processOutput); if (redactedOutput.contains("az login") || redactedOutput.contains("az account set")) { throw logger.logExceptionAsError( - new CredentialUnavailableException("Please run 'az login' to set up account")); + new CredentialUnavailableException( + "AzureCliCredential authentication unavailable." + + " Please run 'az login' to set up account")); } throw logger.logExceptionAsError(new ClientAuthenticationException(redactedOutput, null)); } else { @@ -806,8 +809,10 @@ private Mono checkIMDSAvailable() { connection.connect(); } catch (Exception e) { throw logger.logExceptionAsError( - new CredentialUnavailableException("Connection to IMDS endpoint cannot be established. " - + e.getMessage(), e)); + new CredentialUnavailableException( + "ManagedIdentityCredential authentication unavailable. " + + "Connection to IMDS endpoint cannot be established, " + + e.getMessage() + ".", e)); } finally { if (connection != null) { connection.disconnect(); diff --git a/sdk/identity/azure-identity/src/test/java/com/azure/identity/AzureCliCredentialTest.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/AzureCliCredentialTest.java index e56388555332..c89439fbf463 100644 --- a/sdk/identity/azure-identity/src/test/java/com/azure/identity/AzureCliCredentialTest.java +++ b/sdk/identity/azure-identity/src/test/java/com/azure/identity/AzureCliCredentialTest.java @@ -59,7 +59,7 @@ public void azureCliCredentialWinAzureCLINotInstalledException() throws Exceptio // test AzureCliCredential credential = new AzureCliCredentialBuilder().build(); StepVerifier.create(credential.getToken(request)) - .expectErrorMatches(e -> e instanceof Exception && "Azure CLI not installed".equals(e.getMessage())) + .expectErrorMatches(e -> e instanceof Exception && e.getMessage().contains("Azure CLI not installed")) .verify(); } @@ -71,13 +71,13 @@ public void azureCliCredentialAzNotLogInException() throws Exception { // mock IdentityClient identityClient = PowerMockito.mock(IdentityClient.class); when(identityClient.authenticateWithAzureCli(request)) - .thenReturn(Mono.error(new Exception("Azure not Login"))); + .thenReturn(Mono.error(new Exception("Azure not Login"))); PowerMockito.whenNew(IdentityClient.class).withAnyArguments().thenReturn(identityClient); // test AzureCliCredential credential = new AzureCliCredentialBuilder().build(); StepVerifier.create(credential.getToken(request)) - .expectErrorMatches(e -> e instanceof Exception && "Azure not Login".equals(e.getMessage())) + .expectErrorMatches(e -> e instanceof Exception && e.getMessage().contains("Azure not Login")) .verify(); } @@ -95,7 +95,7 @@ public void azureCliCredentialAuthenticationFailedException() throws Exception { // test AzureCliCredential credential = new AzureCliCredentialBuilder().build(); StepVerifier.create(credential.getToken(request)) - .expectErrorMatches(e -> e instanceof Exception && "other error".equals(e.getMessage())) + .expectErrorMatches(e -> e instanceof Exception && e.getMessage().contains("other error")) .verify(); } 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 0cf94d9bfed8..21657842b1bc 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 @@ -171,15 +171,10 @@ public void testNoCredentialWorks() throws Exception { DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build(); StepVerifier.create(credential.getToken(request)) .expectErrorMatches(t -> t instanceof CredentialUnavailableException && t.getMessage() - .matches("Tried EnvironmentCredential, ManagedIdentityCredential, " - + "SharedTokenCacheCredential[\\$\\w]+\\$\\d*, " - + "IntelliJCredential[\\$\\w]+\\$\\d*, " - + "VisualStudioCodeCredential[\\$\\w]+\\$\\d*, " - + "AzureCliCredential[\\$\\w]+\\$\\d* but [\\$\\w\\s\\.]+")) + .startsWith("EnvironmentCredential authentication unavailable. ")) .verify(); } - @Test public void testCredentialUnavailable() throws Exception { Configuration configuration = Configuration.getGlobalConfiguration(); @@ -210,12 +205,7 @@ public void testCredentialUnavailable() throws Exception { .build(); StepVerifier.create(credential.getToken(request)) .expectErrorMatches(t -> t instanceof CredentialUnavailableException && t.getMessage() - .matches("Tried EnvironmentCredential, " - + "ManagedIdentityCredential[\\$\\w]+\\$\\d*, " - + "SharedTokenCacheCredential, " - + "IntelliJCredential[\\$\\w]+\\$\\d*, " - + "VisualStudioCodeCredential[\\$\\w]+\\$\\d*, " - + "AzureCliCredential but [\\$\\w\\s\\.]+")) + .startsWith("EnvironmentCredential authentication unavailable. ")) .verify(); } }