Skip to content

Commit

Permalink
Simplify azure-identity error messaging (#9022)
Browse files Browse the repository at this point in the history
Co-authored-by: wantedfast <inaccuracy@gmail.com>
  • Loading branch information
Luyunmt and wantedfast authored Jun 22, 2020
1 parent 72d5383 commit cfb7f4c
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -25,6 +26,8 @@
@Immutable
public class ChainedTokenCredential implements TokenCredential {
private final Deque<TokenCredential> credentials;
private final String unavailableError = this.getClass().getSimpleName() + " authentication failed. ---> ";


/**
* Create an instance of chained token credential that aggregates a list of token
Expand All @@ -38,27 +41,26 @@ public class ChainedTokenCredential implements TokenCredential {
public Mono<AccessToken> getToken(TokenRequestContext request) {
List<CredentialUnavailableException> 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);
}));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ public class EnvironmentCredential implements TokenCredential {
public Mono<AccessToken> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,8 @@ public Mono<AccessToken> 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);
}
Expand All @@ -360,7 +361,9 @@ public Mono<AccessToken> 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 {
Expand Down Expand Up @@ -806,8 +809,10 @@ private Mono<Boolean> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

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

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

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

0 comments on commit cfb7f4c

Please sign in to comment.