diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-appservice-java/src/main/java/com/microsoft/azure/toolkit/intellij/legacy/webapp/runner/webappconfig/WebAppRunState.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-appservice-java/src/main/java/com/microsoft/azure/toolkit/intellij/legacy/webapp/runner/webappconfig/WebAppRunState.java index bd9a399470..a83d516a96 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-appservice-java/src/main/java/com/microsoft/azure/toolkit/intellij/legacy/webapp/runner/webappconfig/WebAppRunState.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-appservice-java/src/main/java/com/microsoft/azure/toolkit/intellij/legacy/webapp/runner/webappconfig/WebAppRunState.java @@ -35,6 +35,7 @@ import com.microsoft.azure.toolkit.lib.common.bundle.AzureString; import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException; import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager; import com.microsoft.azure.toolkit.lib.common.model.AbstractAzResource; +import com.microsoft.azure.toolkit.lib.common.model.AbstractAzServiceSubscription; import com.microsoft.azure.toolkit.lib.common.model.AzResource; import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation; import com.microsoft.azure.toolkit.lib.common.operation.OperationContext; @@ -65,6 +66,7 @@ import java.util.stream.Stream; import static com.microsoft.azure.toolkit.intellij.common.AzureBundle.message; import static com.microsoft.azure.toolkit.intellij.connector.IManagedIdentitySupported.*; +import static com.microsoft.azure.toolkit.intellij.connector.dotazure.Profile.IDENTITY_PERMISSION_MESSAGE; public class WebAppRunState extends AzureRunProfileState> { private static final String LIBS_ROOT = "/home/site/wwwroot/libs/"; @@ -128,16 +130,21 @@ public class WebAppRunState extends AzureRunProfileState> { return; } final AbstractAzResource data = (AbstractAzResource) resource.getData(); - final String identity = con.getAuthenticationType() == AuthenticationType.SYSTEM_ASSIGNED_MANAGED_IDENTITY ? - configuration.getPrincipalId() : Objects.requireNonNull(con.getUserAssignedManagedIdentity()).getData().getPrincipalId(); final String identityName = con.getAuthenticationType() == AuthenticationType.SYSTEM_ASSIGNED_MANAGED_IDENTITY ? target instanceof AzResource ? ((AzResource)target).getName() : target.toString() : Objects.requireNonNull(con.getUserAssignedManagedIdentity()).getData().getName(); - if (resource instanceof AzureServiceResource serviceResource && !checkPermission(serviceResource, identity)) { - if (!IManagedIdentitySupported.grantPermission(serviceResource, identity)) { - final String message = String.format("The managed identity %s (%s) doesn't have enough permission to access resource %s.", identity, identityName, resource.getName()); + final String identityPrincipal = con.getAuthenticationType() == AuthenticationType.SYSTEM_ASSIGNED_MANAGED_IDENTITY ? + configuration.getPrincipalId() : Objects.requireNonNull(con.getUserAssignedManagedIdentity()).getData().getPrincipalId(); + final String identityUrl = con.getAuthenticationType() == AuthenticationType.SYSTEM_ASSIGNED_MANAGED_IDENTITY ? + target instanceof AzResource ? ((AzResource)target).getPortalUrl() : StringUtils.EMPTY : + Objects.requireNonNull(con.getUserAssignedManagedIdentity()).getData().getPortalUrl(); + final String resourceUrl = Optional.ofNullable(resource.getData()).filter(r -> r instanceof AbstractAzServiceSubscription) + .map(r -> ((AbstractAzResource) r).getPortalUrl()).orElse(StringUtils.EMPTY); + if (resource instanceof AzureServiceResource serviceResource && !checkPermission(serviceResource, Objects.requireNonNull(identityPrincipal))) { + if (!IManagedIdentitySupported.grantPermission(serviceResource, identityPrincipal)) { + final String message = String.format(IDENTITY_PERMISSION_MESSAGE, identityUrl, identityName, identityPrincipal, resourceUrl, resource.getName()); final Action openIdentityConfigurationAction = getOpenIdentityConfigurationAction(serviceResource); - final Action grantPermissionAction = getGrantPermissionAction(serviceResource, identity); + final Action grantPermissionAction = getGrantPermissionAction(serviceResource, identityPrincipal); AzureMessager.getMessager().warning(message, openIdentityConfigurationAction, grantPermissionAction); } } diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-lib/src/main/java/com/microsoft/azure/toolkit/intellij/common/AzureComboBox.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-lib/src/main/java/com/microsoft/azure/toolkit/intellij/common/AzureComboBox.java index ce9840adaa..dedce08dbd 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-lib/src/main/java/com/microsoft/azure/toolkit/intellij/common/AzureComboBox.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-lib/src/main/java/com/microsoft/azure/toolkit/intellij/common/AzureComboBox.java @@ -267,8 +267,8 @@ public class AzureComboBox extends ComboBox implements AzureFormInputCompo protected void setLoading(final boolean loading) { this.loading = loading; SwingUtilities.invokeLater(() -> { - this.myEditor.rerender(); - Optional.ofNullable(this.myEditor.getEditorComponent()).ifPresent(c -> c.setEnabled(AzureComboBox.this.isEnabled())); + Optional.ofNullable(this.myEditor).ifPresent(AzureComboBoxEditor::rerender); + Optional.ofNullable(this.myEditor).map(BasicComboBoxEditor::getEditorComponent).ifPresent(c -> c.setEnabled(AzureComboBox.this.isEnabled())); this.repaint(); }); } diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-storage-java/src/main/java/com/microsoft/azure/toolkit/intellij/storage/connection/StorageAccountResourceDefinition.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-storage-java/src/main/java/com/microsoft/azure/toolkit/intellij/storage/connection/StorageAccountResourceDefinition.java index 640b56e76e..8bc3311e41 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-storage-java/src/main/java/com/microsoft/azure/toolkit/intellij/storage/connection/StorageAccountResourceDefinition.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-plugin-storage-java/src/main/java/com/microsoft/azure/toolkit/intellij/storage/connection/StorageAccountResourceDefinition.java @@ -16,6 +16,7 @@ import com.microsoft.azure.toolkit.lib.Azure; import com.microsoft.azure.toolkit.lib.auth.AzureCloud; import com.microsoft.azure.toolkit.lib.identities.Identity; import com.microsoft.azure.toolkit.lib.storage.AzureStorageAccount; +import com.microsoft.azure.toolkit.lib.storage.AzuriteStorageAccount; import com.microsoft.azure.toolkit.lib.storage.ConnectionStringStorageAccount; import com.microsoft.azure.toolkit.lib.storage.IStorageAccount; import lombok.AllArgsConstructor; @@ -150,6 +151,14 @@ public class StorageAccountResourceDefinition extends BaseStorageAccountResource return properties; } + @Override + public List getSupportedAuthenticationTypes(Resource resource) { + final Object data = resource.getData(); + return data instanceof ConnectionStringStorageAccount || data instanceof AzuriteStorageAccount ? + Collections.singletonList(AuthenticationType.CONNECTION_STRING) : + super.getSupportedAuthenticationTypes(resource); + } + @Data @AllArgsConstructor public static class TempData { diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-resource-connector-lib/src/main/java/com/microsoft/azure/toolkit/intellij/connector/ConnectorDialog.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-resource-connector-lib/src/main/java/com/microsoft/azure/toolkit/intellij/connector/ConnectorDialog.java index f4d6bfc04f..a889220851 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-resource-connector-lib/src/main/java/com/microsoft/azure/toolkit/intellij/connector/ConnectorDialog.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-resource-connector-lib/src/main/java/com/microsoft/azure/toolkit/intellij/connector/ConnectorDialog.java @@ -28,6 +28,7 @@ import com.microsoft.azure.toolkit.lib.common.form.AzureFormInput; import com.microsoft.azure.toolkit.lib.common.model.AzResource; import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager; import lombok.Getter; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import javax.annotation.Nonnull; @@ -107,6 +108,10 @@ public class ConnectorDialog extends AzureDialog> implements Az this.consumerTypeSelector.addItemListener(this::onResourceOrConsumerTypeChanged); this.resourceTypeSelector.addItemListener(this::onResourceOrConsumerTypeChanged); this.cbAuthenticationType.addItemListener(this::onAuthenticationTypeChanged); + this.cbAuthenticationType.addItemListener(ignore -> { + this.cbIdentity.setRequired(cbAuthenticationType.getValue() == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY); + this.cbIdentity.validateValueAsync(); + }); final Font font = UIManager.getFont("Label.font"); final Color foregroundColor = UIManager.getColor("Label.foreground"); final Color backgroundColor = UIManager.getColor("Label.backgroundColor"); @@ -129,11 +134,25 @@ public class ConnectorDialog extends AzureDialog> implements Az private void onSelectResource(Object o) { final AzureServiceResource value = o instanceof AzureServiceResource ? (AzureServiceResource) this.resourcePanel.getValue() : null; - if (Objects.nonNull(value)) { + final List types = Optional.ofNullable(value).map(resourceDefinition::getSupportedAuthenticationTypes).orElse(Collections.emptyList()); + final List current = cbAuthenticationType.getItems(); + if (!CollectionUtils.isEqualCollection(types, current)) { + updateAuthenticationTypes(types); + } + if (Objects.nonNull(value) && types.contains(AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY)) { cbIdentity.setResource(value); } } + private void updateAuthenticationTypes(@Nonnull final List types) { + final AuthenticationType current = cbAuthenticationType.getValue(); + if (!types.contains(current)) { + this.cbAuthenticationType.clear(); + } + this.cbAuthenticationType.setItemsLoader(() -> types); + this.cbAuthenticationType.reloadItems(); + } + private void onAuthenticationTypeChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { final AuthenticationType authenticationType = this.cbAuthenticationType.getValue(); @@ -228,6 +247,8 @@ public class ConnectorDialog extends AzureDialog> implements Az connection.setAuthenticationType(cbAuthenticationType.getValue()); if (cbAuthenticationType.getValue() == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY) { Optional.ofNullable(cbIdentity.getValue()).map(IdentityResource.Definition.INSTANCE::define).ifPresent(connection::setUserAssignedManagedIdentity); + } else { + connection.setUserAssignedManagedIdentity(null); } return connection; } @@ -288,9 +309,7 @@ public class ConnectorDialog extends AzureDialog> implements Az final List supportedAuthenticationTypes = definition.getSupportedAuthenticationTypes(); this.pnlAuthentication.setVisible(supportedAuthenticationTypes.size() > 1); - this.cbAuthenticationType.clear(); - this.cbAuthenticationType.setItemsLoader(() -> supportedAuthenticationTypes); - this.cbAuthenticationType.reloadItems(); + this.updateAuthenticationTypes(supportedAuthenticationTypes); } } diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-resource-connector-lib/src/main/java/com/microsoft/azure/toolkit/intellij/connector/ResourceDefinition.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-resource-connector-lib/src/main/java/com/microsoft/azure/toolkit/intellij/connector/ResourceDefinition.java index d726d3004f..98f656ad7d 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-resource-connector-lib/src/main/java/com/microsoft/azure/toolkit/intellij/connector/ResourceDefinition.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-resource-connector-lib/src/main/java/com/microsoft/azure/toolkit/intellij/connector/ResourceDefinition.java @@ -89,4 +89,9 @@ public interface ResourceDefinition { } return result; } + + // as for some resource (storage account), supported authentication types may be different for different resource instance + default List getSupportedAuthenticationTypes(@Nonnull Resource resource) { + return getSupportedAuthenticationTypes(); + } } diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-resource-connector-lib/src/main/java/com/microsoft/azure/toolkit/intellij/connector/dotazure/Profile.java b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-resource-connector-lib/src/main/java/com/microsoft/azure/toolkit/intellij/connector/dotazure/Profile.java index 1a402ec917..eadcf2863c 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-resource-connector-lib/src/main/java/com/microsoft/azure/toolkit/intellij/connector/dotazure/Profile.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/azure-intellij-resource-connector-lib/src/main/java/com/microsoft/azure/toolkit/intellij/connector/dotazure/Profile.java @@ -16,6 +16,7 @@ import com.microsoft.azure.toolkit.lib.common.bundle.AzureString; import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException; import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager; import com.microsoft.azure.toolkit.lib.common.model.AbstractAzResource; +import com.microsoft.azure.toolkit.lib.common.model.AbstractAzServiceSubscription; import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation; import com.microsoft.azure.toolkit.lib.common.operation.OperationBundle; import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager; @@ -44,7 +45,7 @@ import static com.microsoft.azure.toolkit.intellij.connector.dotazure.AzureModul @Getter public class Profile { - public static final String NO_PERMISSION_MESSAGE = "The managed identity %s (%s) doesn't have enough permission to access resource %s."; + public static final String IDENTITY_PERMISSION_MESSAGE = "The managed identity %s (%s) doesn't have enough permission to access resource %s."; @Nonnull private final String name; @Nonnull @@ -101,12 +102,16 @@ public class Profile { this.connectionManager.addConnection(connection); // handle user assigned managed identity final Resource identityResource = connection.getUserAssignedManagedIdentity(); - if (Objects.nonNull(identityResource)) { + if (connection.getAuthenticationType() == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY && Objects.nonNull(identityResource)) { this.resourceManager.addResource(identityResource); AzureTaskManager.getInstance().runInBackground("Validating connection", () -> { final String identity = identityResource.getData().getPrincipalId(); - if (resource instanceof AzureServiceResource serviceResource && !checkPermission(serviceResource, identity)) { - final String message = String.format(NO_PERMISSION_MESSAGE, identityResource.getData().getPortalUrl(), identityResource.getName(),identityResource.getData().getPrincipalId(), resource.getName()); + final String identityUrl = identityResource.getData().getPortalUrl(); + final String identityPrincipal = identityResource.getData().getPrincipalId(); + final String resourceUrl = Optional.ofNullable(resource.getData()).filter(r -> r instanceof AbstractAzServiceSubscription) + .map(r -> ((AbstractAzResource) r).getPortalUrl()).orElse(StringUtils.EMPTY); + if (resource instanceof AzureServiceResource serviceResource && !checkPermission(serviceResource, Objects.requireNonNull(identity))) { + final String message = String.format(IDENTITY_PERMISSION_MESSAGE, identityUrl, identityResource.getName(), identityPrincipal, resourceUrl, resource.getName()); final Action openIdentityConfigurationAction = getOpenIdentityConfigurationAction(serviceResource); final Action grantPermissionAction = getGrantPermissionAction(serviceResource, identity); AzureMessager.getMessager().warning(message, grantPermissionAction, openIdentityConfigurationAction);