chore: Impose permission on Git operations (#27954)
## Description This PR checks whether user has permission to create and application in a workspace before doing git operations - Git connect and disconnect from Git. #### PR fixes following issue(s) Fixes #26878
This commit is contained in:
parent
41ee6473a8
commit
17eae14dfc
|
|
@ -18,6 +18,7 @@ import com.appsmith.server.repositories.GitDeployKeysRepository;
|
|||
import com.appsmith.server.services.ce_compatible.GitServiceCECompatibleImpl;
|
||||
import com.appsmith.server.solutions.ApplicationPermission;
|
||||
import com.appsmith.server.solutions.DatasourcePermission;
|
||||
import com.appsmith.server.solutions.WorkspacePermission;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
|
@ -48,6 +49,7 @@ public class GitServiceImpl extends GitServiceCECompatibleImpl implements GitSer
|
|||
PluginService pluginService,
|
||||
DatasourcePermission datasourcePermission,
|
||||
ApplicationPermission applicationPermission,
|
||||
WorkspacePermission workspacePermission,
|
||||
WorkspaceService workspaceService,
|
||||
RedisUtils redisUtils,
|
||||
ObservationRegistry observationRegistry,
|
||||
|
|
@ -73,6 +75,7 @@ public class GitServiceImpl extends GitServiceCECompatibleImpl implements GitSer
|
|||
pluginService,
|
||||
datasourcePermission,
|
||||
applicationPermission,
|
||||
workspacePermission,
|
||||
workspaceService,
|
||||
redisUtils,
|
||||
observationRegistry,
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ import com.appsmith.server.services.UserService;
|
|||
import com.appsmith.server.services.WorkspaceService;
|
||||
import com.appsmith.server.solutions.ApplicationPermission;
|
||||
import com.appsmith.server.solutions.DatasourcePermission;
|
||||
import com.appsmith.server.solutions.WorkspacePermission;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
|
@ -144,6 +145,7 @@ public class GitServiceCEImpl implements GitServiceCE {
|
|||
private final PluginService pluginService;
|
||||
private final DatasourcePermission datasourcePermission;
|
||||
private final ApplicationPermission applicationPermission;
|
||||
private final WorkspacePermission workspacePermission;
|
||||
private final WorkspaceService workspaceService;
|
||||
private final RedisUtils redisUtils;
|
||||
private final ObservationRegistry observationRegistry;
|
||||
|
|
@ -744,7 +746,15 @@ public class GitServiceCEImpl implements GitServiceCE {
|
|||
GitUtils.isRepoPrivate(browserSupportedUrl).cache();
|
||||
|
||||
Mono<Application> connectApplicationMono = profileMono
|
||||
.then(getApplicationById(defaultApplicationId).zipWith(isPrivateRepoMono))
|
||||
.then(getApplicationById(defaultApplicationId))
|
||||
.flatMap(application ->
|
||||
// Check if the user has permission to create app on the workspace, if yes then proceed
|
||||
checkPermissionOnWorkspace(
|
||||
application.getWorkspaceId(),
|
||||
workspacePermission.getApplicationCreatePermission(),
|
||||
"Connect to Git")
|
||||
.thenReturn(application))
|
||||
.zipWith(isPrivateRepoMono)
|
||||
.flatMap(tuple -> {
|
||||
Application application = tuple.getT1();
|
||||
boolean isRepoPrivate = tuple.getT2();
|
||||
|
|
@ -1158,6 +1168,11 @@ public class GitServiceCEImpl implements GitServiceCE {
|
|||
public Mono<Application> detachRemote(String defaultApplicationId) {
|
||||
|
||||
Mono<Application> disconnectMono = getApplicationById(defaultApplicationId)
|
||||
.flatMap(application -> checkPermissionOnWorkspace(
|
||||
application.getWorkspaceId(),
|
||||
workspacePermission.getApplicationCreatePermission(),
|
||||
"Disconnect from Git")
|
||||
.thenReturn(application))
|
||||
.flatMap(defaultApplication -> {
|
||||
if (Optional.ofNullable(defaultApplication.getGitApplicationMetadata())
|
||||
.isEmpty()
|
||||
|
|
@ -1578,6 +1593,14 @@ public class GitServiceCEImpl implements GitServiceCE {
|
|||
AppsmithError.NO_RESOURCE_FOUND, FieldName.APPLICATION_ID, applicationId)));
|
||||
}
|
||||
|
||||
protected Mono<Workspace> checkPermissionOnWorkspace(
|
||||
String workspaceId, AclPermission aclPermission, String operationName) {
|
||||
return workspaceService
|
||||
.findById(workspaceId, aclPermission)
|
||||
.switchIfEmpty(
|
||||
Mono.error(new AppsmithException(AppsmithError.ACTION_IS_NOT_AUTHORIZED, operationName)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to pull application json files from remote repo, make a commit with the changes present in local DB and
|
||||
* make a system commit to remote repo
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import com.appsmith.server.services.WorkspaceService;
|
|||
import com.appsmith.server.services.ce.GitServiceCEImpl;
|
||||
import com.appsmith.server.solutions.ApplicationPermission;
|
||||
import com.appsmith.server.solutions.DatasourcePermission;
|
||||
import com.appsmith.server.solutions.WorkspacePermission;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
|
@ -51,6 +52,7 @@ public class GitServiceCECompatibleImpl extends GitServiceCEImpl implements GitS
|
|||
PluginService pluginService,
|
||||
DatasourcePermission datasourcePermission,
|
||||
ApplicationPermission applicationPermission,
|
||||
WorkspacePermission workspacePermission,
|
||||
WorkspaceService workspaceService,
|
||||
RedisUtils redisUtils,
|
||||
ObservationRegistry observationRegistry,
|
||||
|
|
@ -76,6 +78,7 @@ public class GitServiceCECompatibleImpl extends GitServiceCEImpl implements GitS
|
|||
pluginService,
|
||||
datasourcePermission,
|
||||
applicationPermission,
|
||||
workspacePermission,
|
||||
workspaceService,
|
||||
redisUtils,
|
||||
observationRegistry,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.appsmith.external.models.DatasourceStorageDTO;
|
|||
import com.appsmith.external.models.DefaultResources;
|
||||
import com.appsmith.external.models.JSValue;
|
||||
import com.appsmith.external.models.PluginType;
|
||||
import com.appsmith.external.models.Policy;
|
||||
import com.appsmith.server.actioncollections.base.ActionCollectionService;
|
||||
import com.appsmith.server.constants.FieldName;
|
||||
import com.appsmith.server.datasources.base.DatasourceService;
|
||||
|
|
@ -59,6 +60,7 @@ import com.appsmith.server.services.UserService;
|
|||
import com.appsmith.server.services.WorkspaceService;
|
||||
import com.appsmith.server.solutions.ApplicationPermission;
|
||||
import com.appsmith.server.solutions.EnvironmentPermission;
|
||||
import com.appsmith.server.solutions.WorkspacePermission;
|
||||
import com.appsmith.server.themes.base.ThemeService;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
|
@ -109,6 +111,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.appsmith.external.helpers.AppsmithBeanUtils.copyNestedNonNullProperties;
|
||||
import static com.appsmith.server.acl.AclPermission.MANAGE_APPLICATIONS;
|
||||
|
|
@ -206,6 +209,9 @@ public class GitServiceCETest {
|
|||
@Autowired
|
||||
ApplicationPermission applicationPermission;
|
||||
|
||||
@Autowired
|
||||
WorkspacePermission workspacePermission;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws IOException, GitAPIException {
|
||||
|
||||
|
|
@ -4099,4 +4105,61 @@ public class GitServiceCETest {
|
|||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates an workspace, creates an application in the workspace and removes the
|
||||
* create application permission from the workspace for the api_user.
|
||||
* @return Created Application
|
||||
*/
|
||||
private Application createApplicationAndRemoveCreateAppPermissionFromWorkspace() {
|
||||
User apiUser = userService.findByEmail("api_user").block();
|
||||
|
||||
Workspace toCreate = new Workspace();
|
||||
toCreate.setName("Workspace_" + UUID.randomUUID());
|
||||
Workspace workspace =
|
||||
workspaceService.create(toCreate, apiUser, Boolean.FALSE).block();
|
||||
|
||||
Application testApplication = new Application();
|
||||
testApplication.setWorkspaceId(workspace.getId());
|
||||
testApplication.setName("Test App");
|
||||
Application application1 =
|
||||
applicationPageService.createApplication(testApplication).block();
|
||||
|
||||
// remove create application permission from the workspace for the api user
|
||||
Set<Policy> existingPolicies = workspace.getPolicies();
|
||||
Set<Policy> newPoliciesWithoutExport = existingPolicies.stream()
|
||||
.filter(policy -> !policy.getPermission()
|
||||
.equals(workspacePermission
|
||||
.getApplicationCreatePermission()
|
||||
.getValue()))
|
||||
.collect(Collectors.toSet());
|
||||
workspace.setPolicies(newPoliciesWithoutExport);
|
||||
workspaceRepository.save(workspace).block();
|
||||
return application1;
|
||||
}
|
||||
|
||||
@WithUserDetails("api_user")
|
||||
@Test
|
||||
public void ConnectApplicationToGit_WhenUserDoesNotHaveRequiredPermission_OperationFails() {
|
||||
Application application = createApplicationAndRemoveCreateAppPermissionFromWorkspace();
|
||||
|
||||
GitConnectDTO gitConnectDTO = getConnectRequest("git@github.com:test/testRepo.git", testUserProfile);
|
||||
Mono<Application> applicationMono =
|
||||
gitService.connectApplicationToGit(application.getId(), gitConnectDTO, "baseUrl");
|
||||
|
||||
StepVerifier.create(applicationMono)
|
||||
.expectErrorMessage(AppsmithError.ACTION_IS_NOT_AUTHORIZED.getMessage("Connect to Git"))
|
||||
.verify();
|
||||
}
|
||||
|
||||
@WithUserDetails("api_user")
|
||||
@Test
|
||||
public void detachRemote_WhenUserDoesNotHaveRequiredPermission_OperationFails() {
|
||||
Application application = createApplicationAndRemoveCreateAppPermissionFromWorkspace();
|
||||
Mono<Application> applicationMono = gitService.detachRemote(application.getId());
|
||||
|
||||
StepVerifier.create(applicationMono)
|
||||
.expectErrorMessage(AppsmithError.ACTION_IS_NOT_AUTHORIZED.getMessage("Disconnect from Git"))
|
||||
.verify();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user