diff --git a/Utils/azuretools-core/src/com/microsoft/azure/toolkit/lib/common/rest/RestExceptionHandlerInterceptor.java b/Utils/azuretools-core/src/com/microsoft/azure/toolkit/lib/common/rest/RestExceptionHandlerInterceptor.java new file mode 100644 index 0000000000..769df9f754 --- /dev/null +++ b/Utils/azuretools-core/src/com/microsoft/azure/toolkit/lib/common/rest/RestExceptionHandlerInterceptor.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) Microsoft Corporation + * + * All rights reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and + * to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.microsoft.azure.toolkit.lib.common.rest; + +import com.google.common.base.Throwables; +import com.microsoft.aad.adal4j.AuthenticationException; +import com.microsoft.azuretools.enums.ErrorEnum; +import com.microsoft.azuretools.exception.AzureRuntimeException; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; +import java.net.UnknownHostException; +import java.util.List; + +/** + * Interceptor to handle REST API related exceptions + */ +public class RestExceptionHandlerInterceptor implements Interceptor { + @Override + public Response intercept(final Chain chain) throws IOException { + try { + final Request request = chain.request(); + return chain.proceed(request); + } catch (final Exception ex) { + final List exceptions = Throwables.getCausalChain(ex); + if (exceptions.stream().anyMatch(e -> e instanceof UnknownHostException)) { + throw new AzureRuntimeException(ErrorEnum.UNKNOWN_HOST_EXCEPTION); + } else if (exceptions.stream().anyMatch(e -> e instanceof AuthenticationException)) { + throw new AzureRuntimeException(ErrorEnum.INVALID_AUTHENTICATION); + } + throw ex; + } + } +} diff --git a/Utils/azuretools-core/src/com/microsoft/azuretools/enums/ErrorEnum.java b/Utils/azuretools-core/src/com/microsoft/azuretools/enums/ErrorEnum.java index 2398b06072..038d799beb 100644 --- a/Utils/azuretools-core/src/com/microsoft/azuretools/enums/ErrorEnum.java +++ b/Utils/azuretools-core/src/com/microsoft/azuretools/enums/ErrorEnum.java @@ -28,6 +28,8 @@ public enum ErrorEnum { UNKNOWN_HOST_EXCEPTION(100000, "Encountered an unknown host exception.", "It seems you have an unstable network at the moment, please try again when network is available."), + INVALID_AUTHENTICATION(100401, "Invalid authentication", + "It seems you are not signed in properly, try signing out and then signing in again later"), SOCKET_TIMEOUT_EXCEPTION(100002, "Encountered a socket timeout exception.", "Timeout when accessing azure, please try your operation again."), FAILED_TO_GET_ACCESS_TOKEN_BY_CLI(100003, "Failed to get access token by Azure CLI command.", diff --git a/Utils/azuretools-core/src/com/microsoft/azuretools/sdkmanage/AzureManagerBase.java b/Utils/azuretools-core/src/com/microsoft/azuretools/sdkmanage/AzureManagerBase.java index 344c1465a2..f80e26b9b6 100644 --- a/Utils/azuretools-core/src/com/microsoft/azuretools/sdkmanage/AzureManagerBase.java +++ b/Utils/azuretools-core/src/com/microsoft/azuretools/sdkmanage/AzureManagerBase.java @@ -22,7 +22,6 @@ package com.microsoft.azuretools.sdkmanage; -import com.google.common.base.Throwables; import com.microsoft.azure.AzureEnvironment; import com.microsoft.azure.arm.resources.AzureConfigurable; import com.microsoft.azure.credentials.AzureTokenCredentials; @@ -31,17 +30,14 @@ import com.microsoft.azure.management.appplatform.v2019_05_01_preview.implementation.AppPlatformManager; import com.microsoft.azure.management.resources.Subscription; import com.microsoft.azure.management.resources.Tenant; +import com.microsoft.azure.toolkit.lib.common.rest.RestExceptionHandlerInterceptor; import com.microsoft.azuretools.authmanage.*; -import com.microsoft.azuretools.exception.AzureRuntimeException; -import com.microsoft.azuretools.enums.ErrorEnum; import com.microsoft.azuretools.telemetry.TelemetryInterceptor; import com.microsoft.azuretools.utils.AzureRegisterProviderNamespaces; import com.microsoft.azuretools.utils.Pair; import org.apache.commons.lang3.StringUtils; -import rx.Observable; import java.io.IOException; -import java.net.UnknownHostException; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -128,10 +124,10 @@ public List> getSubscriptionsWithTenant() throws IOEx final Azure.Authenticated authentication = authTenant(getCurrentTenantId()); // could be multi tenant - return all subscriptions for the current account final List tenants = getTenants(authentication); - for (Tenant tenant : tenants) { + for (final Tenant tenant : tenants) { final Azure.Authenticated tenantAuthentication = authTenant(tenant.tenantId()); final List tenantSubscriptions = getSubscriptions(tenantAuthentication); - for (Subscription subscription : tenantSubscriptions) { + for (final Subscription subscription : tenantSubscriptions) { subscriptions.add(new Pair<>(subscription, tenant)); } } @@ -234,38 +230,25 @@ public List getSubscriptions(String tenantId) { return getSubscriptions(authTenant(tenantId)); } - private List getSubscriptions(Azure.Authenticated tenantAuthentication) { - return tenantAuthentication.subscriptions().listAsync() - .onErrorResumeNext(err -> { - LOGGER.warning(err.getMessage()); - return Observable.empty(); - }) + private List getSubscriptions(Azure.Authenticated authentication) { + return authentication.subscriptions().listAsync() .toList() .toBlocking() .singleOrDefault(Collections.emptyList()); } private List getTenants(Azure.Authenticated authentication) { - try { - return authentication.tenants().listAsync() - .toList() - .toBlocking() - .singleOrDefault(Collections.emptyList()); - } catch (Exception err) { - LOGGER.warning(Throwables.getStackTraceAsString(err)); - if (Throwables.getCausalChain(err).stream().filter(e -> e instanceof UnknownHostException).count() > 0) { - throw new AzureRuntimeException(ErrorEnum.UNKNOWN_HOST_EXCEPTION); - } else if (err instanceof AzureRuntimeException) { - throw err; - } - return Collections.emptyList(); - } + return authentication.tenants().listAsync() + .toList() + .toBlocking() + .singleOrDefault(Collections.emptyList()); } protected Azure.Authenticated authTenant(String tenantId) { final AzureTokenCredentials credentials = getCredentials(tenantId); return Azure.configure() .withInterceptor(new TelemetryInterceptor()) + .withInterceptor(new RestExceptionHandlerInterceptor()) .withUserAgent(CommonSettings.USER_AGENT) .authenticate(credentials); } @@ -273,12 +256,16 @@ protected Azure.Authenticated authTenant(String tenantId) { protected AppPlatformManager authSpringCloud(String subscriptionId, String tenantId) { final AzureTokenCredentials credentials = getCredentials(tenantId); return buildAzureManager(AppPlatformManager.configure()) + .withInterceptor(new TelemetryInterceptor()) + .withInterceptor(new RestExceptionHandlerInterceptor()) .authenticate(credentials, subscriptionId); } protected InsightsManager authApplicationInsights(String subscriptionId, String tenantId) { final AzureTokenCredentials credentials = getCredentials(tenantId); return buildAzureManager(InsightsManager.configure()) + .withInterceptor(new TelemetryInterceptor()) + .withInterceptor(new RestExceptionHandlerInterceptor()) .authenticate(credentials, subscriptionId); } }