Skip to content

Commit 33cfc7e

Browse files
authored
Add troubleshooting message link to credential exceptions (Azure#23979)
* Add troubleshooting message link to credential exceptions
1 parent 84b65b0 commit 33cfc7e

9 files changed

+26
-16
lines changed

sdk/identity/Azure.Identity/src/AzureCliCredential.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class AzureCliCredential : TokenCredential
2525
internal const string WinAzureCLIError = "'az' is not recognized";
2626
internal const string AzureCliTimeoutError = "Azure CLI authentication timed out.";
2727
internal const string AzureCliFailedError = "Azure CLI authentication failed due to an unknown error.";
28+
internal const string Troubleshoot = "See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/azclicredential/troubleshoot";
2829
internal const string InteractiveLoginRequired = "Azure CLI could not login. Interactive login is required.";
2930
internal const string CLIInternalError = "CLIInternalError: The command failed with an unexpected error. Here is the traceback:";
3031
private const int CliProcessTimeoutMs = 13000;
@@ -156,7 +157,7 @@ private async ValueTask<AccessToken> RequestCliAccessTokenAsync(bool async, Toke
156157
throw new CredentialUnavailableException(InteractiveLoginRequired);
157158
}
158159

159-
throw new AuthenticationFailedException($"{AzureCliFailedError} {exception.Message}");
160+
throw new AuthenticationFailedException($"{AzureCliFailedError} {Troubleshoot} {exception.Message}");
160161
}
161162

162163
return DeserializeOutput(output);

sdk/identity/Azure.Identity/src/AzurePowerShellCredential.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ public class AzurePowerShellCredential : TokenCredential
2727
private const int PowerShellProcessTimeoutMs = 10000;
2828
internal bool UseLegacyPowerShell { get; set; }
2929

30-
private const string AzurePowerShellFailedError = "Azure PowerShell authentication failed due to an unknown error.";
30+
private const string Troubleshooting = "See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/powershellcredential/troubleshoot";
31+
private const string AzurePowerShellFailedError = "Azure PowerShell authentication failed due to an unknown error. " + Troubleshooting;
3132
private const string AzurePowerShellTimeoutError = "Azure PowerShell authentication timed out.";
3233
internal const string AzurePowerShellNotLogInError = "Please run 'Connect-AzAccount' to set up account.";
3334
internal const string AzurePowerShellModuleNotInstalledError = "Az.Account module >= 2.2.0 is not installed.";

sdk/identity/Azure.Identity/src/CredentialDiagnosticScope.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ public AccessToken Succeeded(AccessToken token)
3636
return token;
3737
}
3838

39-
public Exception FailWrapAndThrow(Exception ex)
39+
public Exception FailWrapAndThrow(Exception ex, string additionalMessage = null)
4040
{
41-
var wrapped = TryWrapException(ref ex);
41+
var wrapped = TryWrapException(ref ex, additionalMessage);
4242
RegisterFailed(ex);
4343

4444
if (!wrapped)
@@ -55,7 +55,7 @@ private void RegisterFailed(Exception ex)
5555
_scopeHandler.Fail(_name, _scope, ex);
5656
}
5757

58-
private bool TryWrapException(ref Exception exception)
58+
private bool TryWrapException(ref Exception exception, string additionalMessageText = null)
5959
{
6060
if (exception is OperationCanceledException || exception is AuthenticationFailedException)
6161
{
@@ -71,8 +71,12 @@ private bool TryWrapException(ref Exception exception)
7171
return true;
7272
}
7373
}
74-
75-
exception = new AuthenticationFailedException($"{_name.Substring(0, _name.IndexOf('.'))} authentication failed: {exception.Message}", exception);
74+
string exceptionMessage = $"{_name.Substring(0, _name.IndexOf('.'))} authentication failed: {exception.Message}";
75+
if (additionalMessageText != null)
76+
{
77+
exceptionMessage = exceptionMessage + $"\n{additionalMessageText}";
78+
}
79+
exception = new AuthenticationFailedException(exceptionMessage, exception);
7680
return true;
7781
}
7882

sdk/identity/Azure.Identity/src/DefaultAzureCredential.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ namespace Azure.Identity
4747
/// </example>
4848
public class DefaultAzureCredential : TokenCredential
4949
{
50-
private const string DefaultExceptionMessage = "DefaultAzureCredential failed to retrieve a token from the included credentials.";
50+
private const string Troubleshooting = "See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/defaultazurecredential/troubleshoot";
51+
private const string DefaultExceptionMessage = "DefaultAzureCredential failed to retrieve a token from the included credentials. " + Troubleshooting;
5152
private const string UnhandledExceptionMessage = "DefaultAzureCredential authentication failed due to an unhandled exception: ";
5253
private static readonly TokenCredential[] s_defaultCredentialChain = GetDefaultAzureCredentialChain(new DefaultAzureCredentialFactory(null), new DefaultAzureCredentialOptions());
5354

sdk/identity/Azure.Identity/src/EnvironmentCredential.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace Azure.Identity
2828
/// </summary>
2929
public class EnvironmentCredential : TokenCredential
3030
{
31-
private const string UnavailableErrorMessage = "EnvironmentCredential authentication unavailable. Environment variables are not fully configured.";
31+
private const string UnavailableErrorMessage = "EnvironmentCredential authentication unavailable. Environment variables are not fully configured. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/environmentcredential/troubleshoot";
3232
private readonly CredentialPipeline _pipeline;
3333
private readonly TokenCredentialOptions _options;
3434

sdk/identity/Azure.Identity/src/ManagedIdentityCredential.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class ManagedIdentityCredential : TokenCredential
2424

2525
private readonly CredentialPipeline _pipeline;
2626
private readonly ManagedIdentityClient _client;
27+
private const string Troubleshooting = "See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/managedidentitycredential/troubleshoot";
2728

2829
/// <summary>
2930
/// Protected constructor for mocking.
@@ -90,7 +91,7 @@ private async ValueTask<AccessToken> GetTokenImplAsync(bool async, TokenRequestC
9091
}
9192
catch (Exception e)
9293
{
93-
throw scope.FailWrapAndThrow(e);
94+
throw scope.FailWrapAndThrow(e, Troubleshooting);
9495
}
9596
}
9697
}

sdk/identity/Azure.Identity/src/UsernamePasswordCredential.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace Azure.Identity
1919
public class UsernamePasswordCredential : TokenCredential
2020
{
2121
private const string NoDefaultScopeMessage = "Authenticating in this environment requires specifying a TokenRequestContext.";
22+
private const string Troubleshooting = "See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/usernamepasswordcredential/troubleshoot";
2223

2324
private readonly string _clientId;
2425
private readonly CredentialPipeline _pipeline;
@@ -185,7 +186,7 @@ private async Task<AuthenticationResult> AuthenticateImplAsync(bool async, Token
185186
}
186187
catch (Exception e)
187188
{
188-
throw scope.FailWrapAndThrow(e);
189+
throw scope.FailWrapAndThrow(e, Troubleshooting);
189190
}
190191
}
191192

@@ -215,7 +216,7 @@ private async Task<AccessToken> GetTokenImplAsync(bool async, TokenRequestContex
215216
}
216217
catch (Exception e)
217218
{
218-
throw scope.FailWrapAndThrow(e);
219+
throw scope.FailWrapAndThrow(e, Troubleshooting);
219220
}
220221
}
221222
}

sdk/identity/Azure.Identity/src/VisualStudioCodeCredential.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class VisualStudioCodeCredential : TokenCredential
2626
private readonly CredentialPipeline _pipeline;
2727
private readonly string _tenantId;
2828
private const string _commonTenant = "common";
29+
private const string Troubleshooting = "See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/vscodecredential/troubleshoot";
2930
internal MsalPublicClient Client { get; }
3031

3132
/// <summary>
@@ -83,12 +84,12 @@ private async ValueTask<AccessToken> GetTokenImplAsync(TokenRequestContext reque
8384
{
8485
throw scope.FailWrapAndThrow(
8586
new CredentialUnavailableException(
86-
$"{nameof(VisualStudioCodeCredential)} authentication unavailable. Token acquisition failed. Ensure that you have authenticated in VSCode Azure Account.",
87+
$"{nameof(VisualStudioCodeCredential)} authentication unavailable. Token acquisition failed. Ensure that you have authenticated in VSCode Azure Account. " + Troubleshooting,
8788
e));
8889
}
8990
catch (Exception e)
9091
{
91-
throw scope.FailWrapAndThrow(e);
92+
throw scope.FailWrapAndThrow(e, Troubleshooting);
9293
}
9394
}
9495

@@ -106,7 +107,7 @@ private string GetStoredCredentials(string environmentName)
106107
}
107108
catch (Exception ex) when (!(ex is OperationCanceledException || ex is CredentialUnavailableException))
108109
{
109-
throw new CredentialUnavailableException("Stored credentials not found. Need to authenticate user in VSCode Azure Account.", ex);
110+
throw new CredentialUnavailableException("Stored credentials not found. Need to authenticate user in VSCode Azure Account. " + Troubleshooting, ex);
110111
}
111112
}
112113

sdk/identity/Azure.Identity/tests/AzureCliCredentialTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public static IEnumerable<object[]> AzureCliExceptionScenarios()
8080
yield return new object[] { AzureCliCredential.AzNotLogIn, AzureCliCredential.AzNotLogIn, typeof(CredentialUnavailableException) };
8181
yield return new object[] { RefreshTokenExpiredError, AzureCliCredential.InteractiveLoginRequired, typeof(CredentialUnavailableException) };
8282
yield return new object[] { AzureCliCredential.CLIInternalError, AzureCliCredential.InteractiveLoginRequired, typeof(CredentialUnavailableException) };
83-
yield return new object[] { "random unknown exception", AzureCliCredential.AzureCliFailedError + " random unknown exception", typeof(AuthenticationFailedException) };
83+
yield return new object[] { "random unknown exception", AzureCliCredential.AzureCliFailedError + " " + AzureCliCredential.Troubleshoot + " random unknown exception", typeof(AuthenticationFailedException) };
8484
}
8585

8686
[Test]

0 commit comments

Comments
 (0)