Require confirm when users need to grant permission to identity

This commit is contained in:
Flanker32 2024-07-28 21:18:22 +08:00
Родитель 35d5e96e90
Коммит e85e9d1637
3 изменённых файлов: 66 добавлений и 39 удалений

Просмотреть файл

@ -5,9 +5,6 @@
package com.microsoft.azure.toolkit.intellij.legacy.webapp.runner.webappconfig;
import com.azure.core.management.profile.AzureProfile;
import com.azure.resourcemanager.authorization.models.BuiltInRole;
import com.azure.resourcemanager.authorization.models.RoleAssignment;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VfsUtil;
import com.microsoft.azure.toolkit.ide.appservice.AppServiceActionsContributor;
@ -67,6 +64,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.microsoft.azure.toolkit.intellij.common.AzureBundle.message;
import static com.microsoft.azure.toolkit.intellij.connector.IManagedIdentitySupported.*;
public class WebAppRunState extends AzureRunProfileState<WebAppBase<?, ?, ?>> {
private static final String LIBS_ROOT = "/home/site/wwwroot/libs/";
@ -132,16 +130,16 @@ public class WebAppRunState extends AzureRunProfileState<WebAppBase<?, ?, ?>> {
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 List<String> roles = data.getRoleAssignments(identity).stream().map(RoleAssignment::roleDefinitionId).toList();
try {
definition.getBuiltInRoles().forEach((id, role) -> {
if (roles.stream().noneMatch(r -> r.endsWith(id))) {
AzureMessager.getMessager().info(String.format("Assign role %s to identity %s...", role, identity));
data.grantPermissionToIdentity(identity, role);
}
});
} catch (final RuntimeException e) {
AzureMessager.getMessager().warning(String.format("Failed to grant permission to identity %s, please try assign correct role to it in portal", identity), e);
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 Action<?> openIdentityConfigurationAction = getOpenIdentityConfigurationAction(serviceResource);
final Action<?> grantPermissionAction = getGrantPermissionAction(serviceResource, identity);
AzureMessager.getMessager().warning(message, openIdentityConfigurationAction, grantPermissionAction);
}
}
});
}

Просмотреть файл

@ -14,6 +14,7 @@ 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.AzResource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -21,12 +22,14 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* Interfaced to indicate that the resource supports managed identity
* <p>
*/
public interface IManagedIdentitySupported<T extends AzResource> {
String FAILED_TO_ASSIGN_MESSAGE = "Failed to grant permission to identity <a href=\"%s\">%s</a>, %s, please try assign correct role to it in portal";
// check whether identity is connected to resource with full permission
@ -53,28 +56,42 @@ public interface IManagedIdentitySupported<T extends AzResource> {
return AzureActionManager.getInstance().getAction(ResourceCommonActionsContributor.OPEN_URL).bind(url).withLabel("Open IAM Configuration");
}
public static boolean grantPermission(@Nonnull AzureServiceResource<?> data, @Nonnull String identity) {
final AzureServiceResource.Definition<?> d = data.getDefinition();
final AzResource r = data.getData();
if (d instanceof IManagedIdentitySupported<?> definition && MapUtils.isNotEmpty(definition.getBuiltInRoles()) && r instanceof AbstractAzResource<?, ?, ?> resource) {
final Map<String, BuiltInRole> builtInRoles = definition.getBuiltInRoles();
final List<String> roles = resource.getRoleAssignments(identity).stream().map(RoleAssignment::roleDefinitionId).toList();
final String rolesStr = builtInRoles.values().stream().map(BuiltInRole::toString).collect(Collectors.joining(","));
final boolean assignRole = AzureMessager.getDefaultMessager().confirm(String.format("Do you want to assign roles (%s) to identity (%s)?", rolesStr, identity), "Assign Required Roles");
if (assignRole) {
try {
Objects.requireNonNull(definition.getBuiltInRoles()).forEach((id, role) -> {
if (roles.stream().noneMatch(ro -> ro.endsWith(id))) {
AzureMessager.getMessager().info(String.format("Assigning role (%s) to identity (%s)...", role, identity));
resource.grantPermissionToIdentity(identity, role);
}
});
AzureMessager.getMessager().info(String.format("Roles (%s) have been assigned to identity (%s)?", rolesStr, identity));
return true;
} catch (final RuntimeException e) {
final String errorMessage = String.format(FAILED_TO_ASSIGN_MESSAGE, resource.getPortalUrl(), identity, e.getMessage());
AzureMessager.getMessager().warning(errorMessage, getOpenIdentityConfigurationAction(data));
}
}
}
return false;
}
@Nullable
public static Action<?> getGrantPermissionAction(@Nonnull AzureServiceResource<?> data, @Nonnull String identity) {
final AzureServiceResource.Definition<?> d = data.getDefinition();
final AzResource r = data.getData();
if (d instanceof IManagedIdentitySupported<?> definition && r instanceof AbstractAzResource<?, ?, ?> resource) {
if (d instanceof IManagedIdentitySupported<?> definition && MapUtils.isNotEmpty(definition.getBuiltInRoles()) && r instanceof AbstractAzResource<?, ?, ?> resource) {
return new Action<>(Action.Id.of("user/common.assign_role.identity"))
.withLabel("Assign Required Roles")
.withIdParam(identity)
.withHandler(ignore -> {
final Map<String, BuiltInRole> builtInRoles = definition.getBuiltInRoles();
final List<String> roles = resource.getRoleAssignments(identity).stream().map(RoleAssignment::roleDefinitionId).toList();
try {
Objects.requireNonNull(definition.getBuiltInRoles()).forEach((id, role) -> {
if (roles.stream().noneMatch(ro -> ro.endsWith(id))) {
AzureMessager.getMessager().info(String.format("Assign role %s to identity %s...", role, identity));
resource.grantPermissionToIdentity(identity, role);
}
});
} catch (final RuntimeException e) {
AzureMessager.getMessager().warning(String.format("Failed to grant permission to identity %s, please try assign correct role to it in portal", identity), e);
}
});
.withHandler(ignore -> grantPermission(data, identity));
}
return null;
}

Просмотреть файл

@ -9,16 +9,17 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.microsoft.azure.toolkit.intellij.connector.Connection;
import com.microsoft.azure.toolkit.intellij.connector.ConnectionTopics;
import com.microsoft.azure.toolkit.intellij.connector.DeploymentTargetTopics;
import com.microsoft.azure.toolkit.intellij.connector.*;
import com.microsoft.azure.toolkit.intellij.facet.AzureFacet;
import com.microsoft.azure.toolkit.lib.common.action.Action;
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.operation.AzureOperation;
import com.microsoft.azure.toolkit.lib.common.operation.OperationBundle;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import com.microsoft.azure.toolkit.lib.identities.Identity;
import io.github.cdimascio.dotenv.internal.DotenvParser;
import io.github.cdimascio.dotenv.internal.DotenvReader;
import lombok.Getter;
@ -33,20 +34,17 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import static com.microsoft.azure.toolkit.intellij.connector.ConnectionTopics.CONNECTION_CHANGED;
import static com.microsoft.azure.toolkit.intellij.connector.IManagedIdentitySupported.*;
import static com.microsoft.azure.toolkit.intellij.connector.dotazure.AzureModule.DOT_ENV;
@Getter
public class Profile {
public static final String NO_PERMISSION_MESSAGE = "The managed identity <a href=\"%s\">%s</a> (%s) doesn't have enough permission to access resource %s.";
@Nonnull
private final String name;
@Nonnull
@ -98,9 +96,23 @@ public class Profile {
public synchronized Future<?> addConnection(@Nonnull Connection<?, ?> connection) {
AzureFacet.addTo(this.module.getModule());
this.resourceManager.addResource(connection.getResource());
final Resource<?> resource = connection.getResource();
this.resourceManager.addResource(resource);
this.connectionManager.addConnection(connection);
Optional.ofNullable(connection.getUserAssignedManagedIdentity()).ifPresent(this.resourceManager::addResource);
// handle user assigned managed identity
final Resource<Identity> identityResource = connection.getUserAssignedManagedIdentity();
if (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 Action<?> openIdentityConfigurationAction = getOpenIdentityConfigurationAction(serviceResource);
final Action<?> grantPermissionAction = getGrantPermissionAction(serviceResource, identity);
AzureMessager.getMessager().warning(message, grantPermissionAction, openIdentityConfigurationAction);
}
});
}
return this.addConnectionToDotEnv(connection);
}