diff --git a/sdk/identity/azure-identity/Troubleshoot.md b/sdk/identity/azure-identity/Troubleshoot.md new file mode 100644 index 000000000000..4362ce1d00e0 --- /dev/null +++ b/sdk/identity/azure-identity/Troubleshoot.md @@ -0,0 +1,223 @@ +## Troubleshooting Azure Identity Authentication Issues +The Azure Identity SDK offers various `TokenCredential` implementations. These implementations tend to throw `CredentialUnavailable` and `ClientAuthentication` exceptions. +The `CredentialUnavailableException` indicates that the credential cannot execute in the current environment setup due to lack of required configuration. +The `ClientAuthenticationException` indicates that the credential was able to run/execute but ran into an authentication issue from the server's end. This can happen due to invalid configuration/details passed in to the credential at construction time. +This troubleshooting guide covers mitigation steps to resolve these exceptions thrown by various `TokenCredential` implementations in the Azure Identity Java client library. + +## Table of contents + - [Troubleshooting Default Azure Credential Authentication Issues](#troubleshooting-default-azure-credential-authentication-issues) + - [Troubleshooting Environment Credential Authentication Issues](#troubleshooting-environment-credential-authentication-issues) + - [Troubleshooting Service Principal Authentication Issues](#troubleshooting-service-principal-authentication-issues) + - [Troubleshooting Username Password Authentication Issues](#troubleshooting-username-password-authentication-issues) + - [Troubleshooting Managed Identity Authentication Issues](#troubleshooting-managed-identity-authentication-issues) + - [Troubleshooting Visual Studio Code Authentication Issues](#troubleshooting-visual-studio-code-authentication-issues) + - [Troubleshooting Azure CLI Authentication Issues](#troubleshooting-azure-cli-authentication-issues) + - [Troubleshooting Azure Powershell Authentication Issues](#troubleshooting-azure-powershell-authentication-issues) + + + +## Troubleshooting Default Azure Credential Authentication Issues. + +### Credential Unavailable Exception +The `DefaultAzureCredential` attempts to retrieve an access token by sequentially invoking a chain of credentials. The `CredentialUnavailableException` in this scenario signifies that all the credentials in the chain failed to retrieve the token in the current environment setup/configuration. You need to follow the configuration instructions for the respective credential you're looking to use via `DefaultAzureCredential` chain, so that the credential can work in your environment. + +Please follow the configuration instructions in the `Credential Unvavailable` section of hte troubleshooting guidelines below for the respective credential/authentication type you're looking to use via `DefaultAzureCredential`: + +| Credential Type | Troubleshoot Guide | +| --- | --- | +| Environment Credential | [Environment Credential Troubleshooting Guide](#troubleshooting-environment-credential-authentication-issues) | +| Managed Identity Credential | [Managed Identity Troubleshooting Guide](#troubleshooting-managed-identity-authentication-issues) | +| Visual Studio Code Credential | [Visual Studio Code Troubleshooting Guide](#troubleshooting-visual-studio-code-authentication-issues) | +| Azure CLI Credential | [Azure CLI Troubleshooting Guide](#troubleshooting-azure-cli-authentication-issues) | +| Azure Powershell Credential | [Azure Powershell Troubleshooting Guide](#troubleshooting-azure-powershell-authentication-issues) | + + + + +## Troubleshooting Environment Credential Authentication Issues. + +### Credential Unavailable Exception + +#### Environment variables not configured +The `EnvironmentCredential` supports Service Principal authentication and Username + Password Authentication. To utilize the desired way of authentication via `EnvironmentCredential`, you need to ensure the environment variables below are configured properly and the application is able to read them. + + +##### Service principal with secret +| Variable Name | Value | +| --- | --- | +AZURE_CLIENT_ID | ID of an Azure Active Directory application. | +AZURE_TENANT_ID |ID of the application's Azure Active Directory tenant. | +AZURE_CLIENT_SECRET | One of the application's client secrets. | + +##### Service principal with certificate +| Variable name | Value | +| --- | --- | +AZURE_CLIENT_ID |ID of an Azure Active Directory application. | +AZURE_TENANT_ID | ID of the application's Azure Active Directory tenant. | +AZURE_CLIENT_CERTIFICATE_PATH | Path to a PEM-encoded certificate file including private key (without password protection). | + +##### Username and password +| Variable name | Value | +| --- | --- | +AZURE_CLIENT_ID | ID of an Azure Active Directory application. | +AZURE_USERNAME | A username (usually an email address). | +AZURE_PASSWORD | The associated password for the given username. | + +### Client Authentication Exception +The `EnvironmentCredential` supports Service Principal authentication and Username + Password Authentication. +Please follow the troubleshooting guidelines below for the respective authentication which you tried and failed. + +| Authentication Type | Troubleshoot Guide | +| --- | --- | +| Service Principal | [Service Principal Auth Troubleshooting Guide](#troubleshooting-username-password-authentication-issues) | +| Username Password | [Username Password Auth Troubleshooting Guide](#troubleshooting-username-password-authentication-issues) | + + + + +## Troubleshooting Username Password Authentication Issues. + +### Two-Factor Authentication Required Error. +The `UsernamePassword` credential works only for users whose two-factor authentication has been disabled in Azure Active Directory. You can change the Multi-Factor Authentication in Azure Portal by following the steps [here](https://docs.microsoft.com/azure/active-directory/authentication/howto-mfa-userstates#change-the-status-for-a-user). + + + + +## Troubleshooting Service Principal Authentication Issues. + +### Illegal/Invalid Argument Issues + +#### Client Id + +The Client ID is the application ID of the registered application / service principal in Azure Active Directory. +It is a required parameter for `ClientSecretCredential` and `ClientCertificateCredential`. If you have already created your service principal +then you can retrieve the client/app id by following the instructions [here](https://docs.microsoft.com/azure/active-directory/develop/howto-create-service-principal-portal#get-tenant-and-app-id-values-for-signing-in). + +#### Tenant Id +The tenant id is te Global Unique Identifier (GUID) that identifies your organization. It is a required parameter for +`ClientSecretCredential` and `ClientCertificateCredential`. If you have already created your service principal +then you can retrieve the client/app id by following the instructions [here](https://docs.microsoft.com/azure/active-directory/develop/howto-create-service-principal-portal#get-tenant-and-app-id-values-for-signing-in). + +### Client Secret Credential Issues + +#### Client Secret Argument +The client secret is the secret string that the application uses to prove its identity when requesting a token, this can also can be referred to as an application password. +If you have already created a service principal you can follow the instructions [here](https://docs.microsoft.com/azure/active-directory/develop/howto-create-service-principal-portal#option-2-create-a-new-application-secret) to get the client secret for your application. + +### Client Certificate Credential Issues + +#### Client Certificate Argument +The `Client Certificate Credential` accepts `pfx` and `pem` certificates. The certificate needs to be associated with your registered application/service principal. To create and associate a certificate with your registered app. please follow the instructions [here](https://docs.microsoft.com/azure/active-directory/develop/howto-create-service-principal-portal#option-1-upload-a-certificate). + +### Create a new service principal +If you're looking to create a new service principal and would like to use that, then follow tne instructions [here](https://docs.microsoft.com/azure/developer/java/sdk/identity-service-principal-auth#create-a-service-principal-with-the-azure-cli) to create a new service principal. + + + + +## Troubleshooting Managed Identity Authentication Issues + +### Credential Unavailable + +#### Connection Timed Out / Connection could not be established / Target Environment could not be determined. +The Managed Identity credential runs only on Azure Hosted machines/servers. So ensure that you are running your application on an +Azure Hosted resource. Currently, Azure Identity SDK supports [Managed Identity Authentication]((https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview)) +in the below listed Azure Services, so ensure you're running your application on one of these resources and have enabled the Managed Identity on +them by following the instructions at their configuration links below. + +Azure Service | Managed Identity Configuration +--- | --- | +[Azure Virtual Machines](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token) | [Configuration Instructions](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/qs-configure-portal-windows-vm) +[Azure App Service](https://docs.microsoft.com/azure/app-service/overview-managed-identity?tabs=java) | [Configuration Instructions](https://docs.microsoft.com/azure/app-service/overview-managed-identity?tabs=java) +[Azure Kubernetes Service](https://docs.microsoft.com/azure/aks/use-managed-identity) | [Configuration Instructions](https://docs.microsoft.com/azure/aks/use-managed-identity) +[Azure Cloud Shell](https://docs.microsoft.com/azure/cloud-shell/msi-authorization) | | +[Azure Arc](https://docs.microsoft.com/azure/azure-arc/servers/managed-identity-authentication) | [Configuration Instructions](https://docs.microsoft.com/azure/azure-arc/servers/security-overview#using-a-managed-identity-with-arc-enabled-servers) +[Azure Service Fabric](https://docs.microsoft.com/azure/service-fabric/concepts-managed-identity) | [Configuration Instructions](https://docs.microsoft.com/azure/service-fabric/configure-existing-cluster-enable-managed-identity-token-service) + + + + +## Troubleshooting Visual Studio Code Authentication Issues + +### Credential Unavailable + +#### Failed To Read VS Code Credentials / Authenticate via Azure Tools plugin in VS Code. +THe `VS Code Credential` failed to read the credential details from the cache. + +The Visual Studio Code authentication is handled by an integration with the Azure Account extension. +To use this form of authentication, ensure that you have installed the Azure Account extension, +then use View > Command Palette to execute the Azure: Sign In command. This command opens a browser window and displays a page that allows you +to sign in to Azure. After you've completed the login process, you can close the browser as directed. Running your application +(either in the debugger or anywhere on the development machine) will use the credential from your sign-in. + +If you already had the Azure Account extension installed and had logged in to your account. Then try logging out and logging in again, as +that will re-populate the cache on the disk and potentially mitigate the error you're getting. + +#### Msal Interaction Required Error +THe `VS Code Credential` was able to read the cached credentials from the cache but the cached token is likely expired. +Log into the Azure Account extension by via View > Command Palette to execute the Azure: Sign In command in the VS Code IDE. + +#### ADFS Tenant Not Supported +The ADFS Tenants are not supported via the Azure Account extension in VS Code currently. +The supported clouds are: + +Azure Cloud | Cloud Authority Host +--- | --- | +AZURE PUBLIC CLOUD | https://login.microsoftonline.com/ +AZURE GERMANY | https://login.microsoftonline.de/ +AZURE CHINA | https://login.chinacloudapi.cn/ +AZURE GOVERNMENT | https://login.microsoftonline.us/ + + + + +## Troubleshooting Azure CLI Authentication Issues + +### Credential Unavailable + +#### Azure CLI Not Installed. +THe `Azure CLI Credential` failed to execute as Azure CLI command line tool is not installed. +To use Azure CLI credential, the Azure CLI needs to be installed, please follow the instructions [here](https://docs.microsoft.com/cli/azure/install-azure-cli) +to install it for your platform and then try running the credential again. + +#### Azure account not logged in. +The `Azure CLI Credential` utilizes the current logged in Azure user in Azure CLI to fetch an access token. +You need to log in to your account in Azure CLI via `az login` command. You can further read instructions to [Sign in with Azure CLI](https://docs.microsoft.com/cli/azure/authenticate-azure-cli). +Once logged in try running the credential again. + +### Illegal State +#### Safe Working Directory Not Located. +The `Azure CLI Credential` was not able to locate a value for System Environment property `SystemRoot` to execute in. +Please ensure the `SystemRoot` environment variable is configured to a safe working directory and then try running the credential again. + + + + +## Troubleshooting Azure Powershell Authentication Issues + +### Credential Unavailable + +#### Powershell not installed. + +The `Azure Powershell Credential` utilizes the locally installed `Powershell` command line tool to fetch an access token. Please ensure it is installed on your platform by following the instructions [here](https://docs.microsoft.com/powershell/scripting/install/installing-powershell?view=powershell-7.1) and then run the credential again. + +#### Azure Az Module Not Installed. +The `Azure Powershell Credential` failed to execute as Azure az module is not installed. +To use Azure Powershell credential, the Azure az module needs to be installed, please follow the instructions [here](https://docs.microsoft.com/powershell/azure/install-az-ps?view=azps-6.3.0) +to install it for your platform and then try running the credential again. + +#### Azure account not logged in. +The `Azure Powershell Credential` utilizes the current logged in Azure user in Azure Powershell to fetch an access token. +You need to log in to your account in Azure Powershell via `Connect-AzAccount` command. You can further read instructions to [Sign in with Azure Powershell](https://docs.microsoft.com/powershell/azure/authenticate-azureps?view=azps-6.3.0). +Once logged in try running the credential again. + + +#### Deserialization error. +The `Azure Powershell Credential` was able to retrieve a response from the Azure Powershell when attempting to get an access token but failed +to parse that response. +In your local powershell window, run the following command to ensure that Azure Powershell is returning an access token in correct format. + +```pwsh +Get-AzAccessToken -ResourceUrl "" +``` +In the event above command is not working properly, follow the instructions to resolve the Azure Powershell issue being faced and then try running the credential again. 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 8cef48f2a993..d1b1826467bf 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 @@ -25,6 +25,8 @@ */ @Immutable public class ChainedTokenCredential implements TokenCredential { + private static final String TROUBLESHOOT_MESSAGE = "To mitigate this issue, please refer to the troubleshooting " + + "guidelines here at https://aka.ms/azure-identity-java-default-azure-credential-troubleshoot"; private final ClientLogger logger = new ClientLogger(getClass()); private final List credentials; private final String unavailableError = this.getClass().getSimpleName() + " authentication failed. ---> "; @@ -73,8 +75,8 @@ public Mono getToken(TokenRequestContext request) { 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(), - last.getCause()); + last = new CredentialUnavailableException(current.getMessage() + "\r\n" + last.getMessage() + + (z == 0 ? TROUBLESHOOT_MESSAGE : "")); } 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 ddedd404519d..e3cd57162403 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 @@ -123,7 +123,9 @@ public Mono getToken(TokenRequestContext request) { if (tokenCredential == null) { return Mono.error(logger.logExceptionAsError(new CredentialUnavailableException( "EnvironmentCredential authentication unavailable." - + " Environment variables are not fully configured."))); + + " Environment variables are not fully configured." + + "Visit https://aka.ms/azsdk/net/identity/environmentcredential/troubleshoot to troubleshoot" + + "this issue."))); } else { return tokenCredential.getToken(request); } diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/ManagedIdentityCredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/ManagedIdentityCredential.java index d5129fb369c2..330291782bf7 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/ManagedIdentityCredential.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/ManagedIdentityCredential.java @@ -72,7 +72,9 @@ public Mono getToken(TokenRequestContext request) { if (managedIdentityServiceCredential == null) { return Mono.error(logger.logExceptionAsError( new CredentialUnavailableException("ManagedIdentityCredential authentication unavailable. " - + "The Target Azure platform could not be determined from environment variables."))); + + "The Target Azure platform could not be determined from environment variables." + + "Visit https://aka.ms/azsdk/net/identity/managedidentitycredential/troubleshoot to " + + "troubleshoot this issue."))); } return managedIdentityServiceCredential.authenticate(request) .doOnSuccess(t -> logger.info("Azure Identity => Managed Identity environment: {}", 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 12f295b8ea9f..556d46877f09 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 @@ -206,7 +206,9 @@ private Mono getConfidentialClientApplication() { } } else { return Mono.error(logger.logExceptionAsError( - new IllegalArgumentException("Must provide client secret or client certificate path"))); + new IllegalArgumentException("Must provide client secret or client certificate path." + + " To mitigate this issue, please refer to the troubleshooting guidelines here at " + + "https://aka.ms/azsdk/java/identity/serviceprincipalauthentication/troubleshoot"))); } ConfidentialClientApplication.Builder applicationBuilder = @@ -309,6 +311,7 @@ private Mono getPublicClientApplication(boolean sharedT public Mono authenticateWithIntelliJ(TokenRequestContext request) { try { IntelliJCacheAccessor cacheAccessor = new IntelliJCacheAccessor(options.getIntelliJKeePassDatabasePath()); + IntelliJAuthMethodDetails authDetails = cacheAccessor.getAuthDetailsIfAvailable(); String authType = authDetails.getAuthMethod(); if (authType.equalsIgnoreCase("SP")) { @@ -340,7 +343,10 @@ public Mono authenticateWithIntelliJ(TokenRequestContext request) { return Mono.error(e); } } else if (authType.equalsIgnoreCase("DC")) { - + logger.verbose("IntelliJ Authentication => Device Code Authentication scheme detected in Azure Tools" + + " for IntelliJ Plugin."); + logger.verbose("Checking if the provided tenant is an ADFS tenant or not. The ADFS tenants are not" + + " supported via IntelliJ Authentication currently." ); if (isADFSTenant()) { return Mono.error(new CredentialUnavailableException("IntelliJCredential " + "authentication unavailable. ADFS tenant/authorities are not supported.")); @@ -361,6 +367,9 @@ public Mono authenticateWithIntelliJ(TokenRequestContext request) { .map(MsalToken::new)); } else { + logger.verbose("IntelliJ Authentication = > Only Service Principal and Device Code Authentication" + + " schemes are currently supported via IntelliJ Credential currently. Please ensure you used one" + + " of those schemes from Azure Tools for IntelliJ plugin."); throw logger.logExceptionAsError(new CredentialUnavailableException( "IntelliJ Authentication not available." + " Please login with Azure Tools for IntelliJ plugin in the IDE.")); @@ -406,14 +415,20 @@ public Mono authenticateWithAzureCli(TokenRequestContext request) { } ProcessBuilder builder = new ProcessBuilder(starter, switcher, command.toString()); + logger.verbose("Azure CLI Authentication => Retrieving safe working directory to execute Azure CLI" + + " commands from."); String workingDirectory = getSafeWorkingDirectory(); if (workingDirectory != null) { builder.directory(new File(workingDirectory)); } else { throw logger.logExceptionAsError(new IllegalStateException("A Safe Working directory could not be" - + " found to execute CLI command from.")); + + " found to execute CLI command from. To mitigate this issue, please refer to the troubleshooting " + + " guidelines here at https://aka.ms/azsdk/java/identity/azclicredential/troubleshoot")); } builder.redirectErrorStream(true); + + logger.verbose("Azure CLI Authentication => Invoking the process to execute Azure CLI commands and " + + "retrieve an Access Token."); Process process = builder.start(); reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")); @@ -426,8 +441,10 @@ public Mono authenticateWithAzureCli(TokenRequestContext request) { } if (line.startsWith(WINDOWS_PROCESS_ERROR_MESSAGE) || line.matches(LINUX_MAC_PROCESS_ERROR_MESSAGE)) { throw logger.logExceptionAsError( - new CredentialUnavailableException( - "AzureCliCredential authentication unavailable. Azure CLI not installed")); + new CredentialUnavailableException( + "AzureCliCredential authentication unavailable. Azure CLI not installed." + + "To mitigate this issue, please refer to the troubleshooting guidelines here at " + + "https://aka.ms/azsdk/java/identity/azclicredential/troubleshoot")); } output.append(line); } @@ -440,9 +457,11 @@ 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( - "AzureCliCredential authentication unavailable." - + " Please run 'az login' to set up account")); + new CredentialUnavailableException( + "AzureCliCredential authentication unavailable." + + " Please run 'az login' to set up account. To further mitigate this" + + " issue, please refer to the troubleshooting guidelines here at " + + "https://aka.ms/azsdk/java/identity/azclicredential/troubleshoot")); } throw logger.logExceptionAsError(new ClientAuthenticationException(redactedOutput, null)); } else { @@ -450,6 +469,9 @@ public Mono authenticateWithAzureCli(TokenRequestContext request) { new ClientAuthenticationException("Failed to invoke Azure CLI ", null)); } } + + logger.verbose("Azure CLI Authentication => A token response was received from Azure CLI, deserializng the" + + " response into an Access Token."); Map objectMap = SERIALIZER_ADAPTER.deserialize(processOutput, Map.class, SerializerEncoding.JSON); String accessToken = objectMap.get("accessToken"); @@ -503,7 +525,9 @@ public Mono authenticateWithAzurePowerShell(TokenRequestContext req .onErrorResume(t -> { if (!t.getClass().getSimpleName().equals("CredentialUnavailableException")) { return Mono.error(new ClientAuthenticationException( - "Azure Powershell authentication failed. Error Details: " + t.getMessage(), + "Azure Powershell authentication failed. Error Details: " + t.getMessage() + + ". To mitigate this issue, please refer to the troubleshooting guidelines here at " + + "https://aka.ms/azsdk/java/identity/powershellcredential/troubleshoot", null, t)); } exceptions.add((CredentialUnavailableException) t); @@ -518,7 +542,9 @@ public Mono authenticateWithAzurePowerShell(TokenRequestContext req last = new CredentialUnavailableException("Azure Powershell authentication failed using default" + "powershell(pwsh) with following error: " + current.getMessage() + "\r\n" + "Azure Powershell authentication failed using powershell-core(powershell)" - + " with following error: " + last.getMessage(), + + " with following error: " + last.getMessage() + + (z == 0 ? ". To mitigate this issue, please refer to the troubleshooting guidelines here at " + + "https://aka.ms/azsdk/java/identity/powershellcredential/troubleshoot" : ""), last.getCause()); } return Mono.error(last); @@ -528,38 +554,52 @@ public Mono authenticateWithAzurePowerShell(TokenRequestContext req private Mono getAccessTokenFromPowerShell(TokenRequestContext request, PowershellManager powershellManager) { return powershellManager.initSession() - .flatMap(manager -> manager.runCommand("Import-Module Az.Accounts -MinimumVersion 2.2.0 -PassThru") - .flatMap(output -> { - if (output.contains("The specified module 'Az.Accounts' with version '2.2.0' was not loaded " - + "because no valid module file")) { - return Mono.error(new CredentialUnavailableException( - "Az.Account module with version >= 2.2.0 is not installed. It needs to be installed to use" - + "Azure PowerShell Credential.")); - } - StringBuilder accessTokenCommand = new StringBuilder("Get-AzAccessToken -ResourceUrl "); - accessTokenCommand.append(ScopeUtil.scopesToResource(request.getScopes())); - accessTokenCommand.append(" | ConvertTo-Json"); - return manager.runCommand(accessTokenCommand.toString()) - .flatMap(out -> { - if (out.contains("Run Connect-AzAccount to login")) { - return Mono.error(new CredentialUnavailableException( - "Run Connect-AzAccount to login to Azure account in PowerShell.")); - } - try { - Map objectMap = SERIALIZER_ADAPTER.deserialize(out, Map.class, - SerializerEncoding.JSON); - String accessToken = objectMap.get("Token"); - String time = objectMap.get("ExpiresOn"); - OffsetDateTime expiresOn = OffsetDateTime.parse(time) - .withOffsetSameInstant(ZoneOffset.UTC); - return Mono.just(new AccessToken(accessToken, expiresOn)); - } catch (IOException e) { - return Mono.error(logger - .logExceptionAsError(new CredentialUnavailableException( - "Encountered error when deserializing response from Azure Power Shell.", e))); - } - }); - })).doFinally(ignored -> powershellManager.close()); + .flatMap(manager -> { + String azAccountsCommand = "Import-Module Az.Accounts -MinimumVersion 2.2.0 -PassThru"; + logger.verbose("Azure Powershell Authentication = > Checking if Az.Accounts module is installed or " + + "not in Azure Powershell by executing this command `%s`. This module is required to execute Azure" + + " Powershell Credential.", azAccountsCommand); + return manager.runCommand(azAccountsCommand) + .flatMap(output -> { + if (output.contains("The specified module 'Az.Accounts' with version '2.2.0' was not loaded " + + "because no valid module file")) { + return Mono.error(new CredentialUnavailableException( + "Az.Account module with version >= 2.2.0 is not installed. It needs to be installed to" + + " use Azure PowerShell Credential.")); + } + logger.verbose("Az.accounts module was found installed."); + StringBuilder accessTokenCommand = new StringBuilder("Get-AzAccessToken -ResourceUrl "); + accessTokenCommand.append(ScopeUtil.scopesToResource(request.getScopes())); + accessTokenCommand.append(" | ConvertTo-Json"); + String command = accessTokenCommand.toString(); + logger.verbose("Azure Powershell Authentication => Executing the command `%s` in Azure " + + "Powershell to retrieve the Access Token.", + accessTokenCommand); + return manager.runCommand(accessTokenCommand.toString()) + .flatMap(out -> { + if (out.contains("Run Connect-AzAccount to login")) { + return Mono.error(new CredentialUnavailableException( + "Run Connect-AzAccount to login to Azure account in PowerShell.")); + } + + try { + logger.verbose("Azure Powershell Authentication => Attempting to deserialize the " + + "received response from Azure Powershell."); + Map objectMap = SERIALIZER_ADAPTER.deserialize(out, Map.class, + SerializerEncoding.JSON); + String accessToken = objectMap.get("Token"); + String time = objectMap.get("ExpiresOn"); + OffsetDateTime expiresOn = OffsetDateTime.parse(time) + .withOffsetSameInstant(ZoneOffset.UTC); + return Mono.just(new AccessToken(accessToken, expiresOn)); + } catch (IOException e) { + return Mono.error(logger + .logExceptionAsError(new CredentialUnavailableException( + "Encountered error when deserializing response from Azure Power Shell.", e))); + } + }); + }); + }).doFinally(ignored -> powershellManager.close()); } /** @@ -610,7 +650,9 @@ public Mono authenticateWithUsernamePassword(TokenRequestContext requ return pc.acquireToken(userNamePasswordParametersBuilder.build()); } )).onErrorMap(t -> new ClientAuthenticationException("Failed to acquire token with username and " - + "password", null, t)).map(MsalToken::new); + + "password. To mitigate this issue, please refer to the troubleshooting guidelines " + + "here at https://aka.ms/azsdk/net/identity/usernamepasswordcredential/troubleshoot", + null, t)).map(MsalToken::new); } /** @@ -719,16 +761,24 @@ public Mono authenticateWithDeviceCode(TokenRequestContext request, */ public Mono authenticateWithVsCodeCredential(TokenRequestContext request, String cloud) { + logger.verbose("VS Code Authentication => Checking if the provided is an ADFS tenant or not. The ADFS tenants" + + " are not supported via Visual Studio Authentication currently." ); if (isADFSTenant()) { return Mono.error(new CredentialUnavailableException("VsCodeCredential " - + "authentication unavailable. ADFS tenant/authorities are not supported.")); + + "authentication unavailable. ADFS tenant/authorities are not supported. " + + "To mitigate this issue, please refer to the troubleshooting guidelines here at " + + "https://aka.ms/azsdk/net/identity/vscodecredential/troubleshoot")); } VisualStudioCacheAccessor accessor = new VisualStudioCacheAccessor(); + logger.verbose("VS Code Authentication => Starting to retrieve the cached refresh token from VS Code Azure" + + " Extension's cache"); String credential = accessor.getCredentials("VS Code Azure", cloud); + logger.verbose("VS Code Authentication => Retrieved the cached refresh token from VS Code Azure Extension's" + + " cache."); RefreshTokenParameters.RefreshTokenParametersBuilder parametersBuilder = RefreshTokenParameters - .builder(new HashSet<>(request.getScopes()), credential); + .builder(new HashSet<>(request.getScopes()), credential); if (request.getClaims() != null) { ClaimsRequest customClaimRequest = CustomClaimRequest.formatAsClaimsRequest(request.getClaims()); @@ -738,9 +788,14 @@ public Mono authenticateWithVsCodeCredential(TokenRequestContext requ return publicClientApplicationAccessor.getValue() .flatMap(pc -> Mono.fromFuture(pc.acquireToken(parametersBuilder.build())) .onErrorResume(t -> { + logger.verbose("VS Code Authentication => Encountered an error as the refresh token found in the" + + " VS code cache was expired. Please login again interactively in VS Code Azure Extension" + + " plugin to mitigate this issue."); if (t instanceof MsalInteractionRequiredException) { return Mono.error(new CredentialUnavailableException("Failed to acquire token with" - + " VS code credential", t)); + + " VS code credential." + + " To mitigate this issue, please refer to the troubleshooting guidelines here at " + + "https://aka.ms/azsdk/net/identity/vscodecredential/troubleshoot", t)); } return Mono.error(new ClientAuthenticationException("Failed to acquire token with" + " VS code credential", null, t)); diff --git a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IntelliJCacheAccessor.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IntelliJCacheAccessor.java index e326805a4801..281cfaefa912 100644 --- a/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IntelliJCacheAccessor.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IntelliJCacheAccessor.java @@ -247,6 +247,9 @@ public IntelliJAuthMethodDetails getAuthDetailsIfAvailable() throws IOException break; } } + logger.verbose("IntelliJ Authentication => Reading in Azure Tools for IntelliJ Plugin's metadata file" + + " located at `%s`. This file contains authentication scheme details used when logging via" + + " Azure Plugin in IntelliJ IDE.", authFile.getAbsolutePath()); if (authFile == null || !authFile.exists()) { throw logger.logExceptionAsError( new CredentialUnavailableException(INTELLIJ_CREDENTIAL_NOT_AVAILABLE_ERROR)); @@ -256,16 +259,24 @@ public IntelliJAuthMethodDetails getAuthDetailsIfAvailable() throws IOException String authType = authMethodDetails.getAuthMethod(); if (CoreUtils.isNullOrEmpty(authType)) { + logger.verbose("IntelliJ Authentication => Authentication Type could not be found in Azure Tools for" + + " IntelliJ Plugin's metadata file located at `%s`.", authFile.getAbsolutePath()); throw logger.logExceptionAsError( new CredentialUnavailableException(INTELLIJ_CREDENTIAL_NOT_AVAILABLE_ERROR)); } if (authType.equalsIgnoreCase("SP")) { if (CoreUtils.isNullOrEmpty(authMethodDetails.getCredFilePath())) { + logger.verbose("IntelliJ Authentication => Service Principal Authentication Detected but file path to " + + "service principal could not be found in Azure Tools for IntelliJ Plugin's metadata file located" + + " at `%s`.", authFile.getAbsolutePath()); throw logger.logExceptionAsError( new CredentialUnavailableException(INTELLIJ_CREDENTIAL_NOT_AVAILABLE_ERROR)); } } else if (authType.equalsIgnoreCase("DC")) { if (CoreUtils.isNullOrEmpty(authMethodDetails.getAccountEmail())) { + logger.verbose("IntelliJ Authentication => Device Code Authentication Detected but user email info used" + + " for logging in could not be found in Azure Tools for IntelliJ Plugin's metadata file located" + + " at `%s`.", authFile.getAbsolutePath()); throw logger.logExceptionAsError( new CredentialUnavailableException(INTELLIJ_CREDENTIAL_NOT_AVAILABLE_ERROR)); }