Added action inheritance for permissions during create. No update permissions for action added. Fixed the existing test cases to run with the new code.

TODO : Add test cases for action permissions.
This commit is contained in:
Trisha Anand 2020-05-08 15:39:36 +00:00
parent c12d83caa5
commit b7435e546f
5 changed files with 138 additions and 18 deletions

View File

@ -6,16 +6,20 @@ import com.appsmith.external.models.DatasourceConfiguration;
import com.appsmith.external.models.PaginationField;
import com.appsmith.external.models.PaginationType;
import com.appsmith.external.models.Param;
import com.appsmith.external.models.Policy;
import com.appsmith.external.models.Provider;
import com.appsmith.external.plugins.PluginExecutor;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.acl.PolicyGenerator;
import com.appsmith.server.constants.AnalyticsEvents;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.Action;
import com.appsmith.server.domains.ActionProvider;
import com.appsmith.server.domains.Datasource;
import com.appsmith.server.domains.Page;
import com.appsmith.server.domains.Plugin;
import com.appsmith.server.domains.PluginType;
import com.appsmith.server.domains.User;
import com.appsmith.server.dtos.ExecuteActionDTO;
import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException;
@ -56,6 +60,8 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static com.appsmith.server.acl.AclPermission.MANAGE_PAGES;
import static com.appsmith.server.acl.AclPermission.READ_PAGES;
import static com.appsmith.server.helpers.MustacheHelper.extractMustacheKeysFromJson;
@Slf4j
@ -71,6 +77,7 @@ public class ActionServiceImpl extends BaseService<ActionRepository, Action, Str
private final PluginExecutorHelper pluginExecutorHelper;
private final SessionUserService sessionUserService;
private final MarketplaceService marketplaceService;
private final PolicyGenerator policyGenerator;
@Autowired
public ActionServiceImpl(Scheduler scheduler,
@ -86,7 +93,8 @@ public class ActionServiceImpl extends BaseService<ActionRepository, Action, Str
DatasourceContextService datasourceContextService,
PluginExecutorHelper pluginExecutorHelper,
SessionUserService sessionUserService,
MarketplaceService marketplaceService) {
MarketplaceService marketplaceService,
PolicyGenerator policyGenerator) {
super(scheduler, validator, mongoConverter, reactiveMongoTemplate, repository, analyticsService);
this.repository = repository;
this.datasourceService = datasourceService;
@ -97,6 +105,7 @@ public class ActionServiceImpl extends BaseService<ActionRepository, Action, Str
this.pluginExecutorHelper = pluginExecutorHelper;
this.sessionUserService = sessionUserService;
this.marketplaceService = marketplaceService;
this.policyGenerator = policyGenerator;
}
private Boolean validateActionName(String name) {
@ -111,15 +120,31 @@ public class ActionServiceImpl extends BaseService<ActionRepository, Action, Str
if (action.getId() != null) {
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, "id"));
}
return sessionUserService.getCurrentUser()
.map(user -> user.getCurrentOrganizationId())
.map(orgId -> {
if (action.getPageId() == null || action.getPageId().isBlank()) {
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.PAGE_ID));
}
Mono<User> userMono = sessionUserService
.getCurrentUser()
.cache();
return pageService
.findById(action.getPageId(), READ_PAGES)
.zipWith(userMono)
.map(tuple -> {
Page page = tuple.getT1();
User user = tuple.getT2();
// Inherit the action policies from the page.
generateAndSetActionPolicies(page, user, action);
Datasource datasource = action.getDatasource();
if (datasource != null) {
datasource.setOrganizationId(orgId);
datasource.setOrganizationId(user.getCurrentOrganizationId());
action.setDatasource(datasource);
}
action.setOrganizationId(orgId);
action.setOrganizationId(user.getCurrentOrganizationId());
return action;
})
.flatMap(this::validateAndSaveActionToRepository);
@ -600,4 +625,13 @@ public class ActionServiceImpl extends BaseService<ActionRepository, Action, Str
return providerUpdatedAction;
});
}
private void generateAndSetActionPolicies(Page page, User user, Action action) {
Set<Policy> policySet = page.getPolicies().stream()
.filter(policy -> policy.getPermission().equals(MANAGE_PAGES.getValue())
|| policy.getPermission().equals(READ_PAGES.getValue()))
.collect(Collectors.toSet());
Set<Policy> documentPolicies = policyGenerator.getAllChildPolicies(user, policySet, Page.class);
action.setPolicies(documentPolicies);
}
}

View File

@ -33,6 +33,7 @@ import static com.appsmith.server.acl.AclPermission.MANAGE_PAGES;
import static com.appsmith.server.acl.AclPermission.ORGANIZATION_MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.READ_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.READ_ORGANIZATIONS;
import static com.appsmith.server.acl.AclPermission.READ_PAGES;
import static com.appsmith.server.acl.AclPermission.READ_USERS;
import static com.appsmith.server.acl.AclPermission.USER_MANAGE_ORGANIZATIONS;
import static org.springframework.data.mongodb.core.query.Criteria.where;
@ -73,6 +74,10 @@ public class SeedMongoData {
.users(Set.of(API_USER_EMAIL))
.build();
Policy readPagePolicy = Policy.builder().permission(READ_PAGES.getValue())
.users(Set.of(API_USER_EMAIL))
.build();
Policy readOrgPolicy = Policy.builder().permission(READ_ORGANIZATIONS.getValue())
.users(Set.of(API_USER_EMAIL))
.build();
@ -102,7 +107,7 @@ public class SeedMongoData {
{"Another TestApplications", Set.of(manageAppPolicy, readAppPolicy)}
};
Object[][] pageData = {
{"validPageName", Set.of(managePagePolicy)}
{"validPageName", Set.of(managePagePolicy, readPagePolicy)}
};
Object[][] pluginData = {
{"Installed Plugin Name", PluginType.API, "installed-plugin"},

View File

@ -1,11 +1,16 @@
package com.appsmith.server.services;
import com.appsmith.external.models.ActionConfiguration;
import com.appsmith.external.models.Policy;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.Action;
import com.appsmith.server.domains.Application;
import com.appsmith.server.domains.Page;
import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -18,7 +23,10 @@ import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.util.Map;
import java.util.Set;
import static com.appsmith.server.acl.AclPermission.MANAGE_ACTIONS;
import static com.appsmith.server.acl.AclPermission.READ_ACTIONS;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@ -29,12 +37,76 @@ public class ActionServiceTest {
@Autowired
ActionService actionService;
@Autowired
ApplicationPageService applicationPageService;
@Autowired
PageService pageService;
Application testApp = null;
Page testPage = null;
int i = 0;
@Before
@WithUserDetails(value = "api_user")
public void setup() {
if (testApp == null && testPage == null) {
//Create application and page which will be used by the tests to create actions for.
Application application = new Application();
application.setName("ActionServiceTest-App-" + String.valueOf(i));
i++;
testApp = applicationPageService.createApplication(application).block();
testPage = pageService.getById(testApp.getPages().get(0).getId()).block();
}
}
@After
@WithUserDetails(value = "api_user")
public void cleanup() {
applicationPageService.deleteApplication(testApp.getId()).block();
testApp = null;
testPage = null;
}
@Test
@WithUserDetails(value = "api_user")
public void createValidActionAndCheckPermissions() {
Policy manageActionPolicy = Policy.builder().permission(MANAGE_ACTIONS.getValue())
.users(Set.of("api_user"))
.build();
Policy readActionPolicy = Policy.builder().permission(READ_ACTIONS.getValue())
.users(Set.of("api_user"))
.build();
Action action = new Action();
action.setName("validAction");
action.setPageId(testPage.getId());
ActionConfiguration actionConfiguration = new ActionConfiguration();
actionConfiguration.setHttpMethod(HttpMethod.GET);
action.setActionConfiguration(actionConfiguration);
Mono<Action> actionMono = actionService.create(action);
StepVerifier
.create(actionMono)
.assertNext(createdAction -> {
assertThat(createdAction.getId()).isNotEmpty();
assertThat(createdAction.getName()).isEqualTo(action.getName());
assertThat(createdAction.getPolicies()).containsAll(Set.of(manageActionPolicy, readActionPolicy));
})
.verifyComplete();
}
@Test
@WithUserDetails(value = "api_user")
public void createValidActionWithJustName() {
Action action = new Action();
action.setName("randomActionName");
action.setPageId("randomPageId");
action.setPageId(testPage.getId());
ActionConfiguration actionConfiguration = new ActionConfiguration();
actionConfiguration.setHttpMethod(HttpMethod.GET);
action.setActionConfiguration(actionConfiguration);
@ -56,7 +128,7 @@ public class ActionServiceTest {
public void createValidActionNullActionConfiguration() {
Action action = new Action();
action.setName("randomActionName2");
action.setPageId("randomPageId");
action.setPageId(testPage.getId());
Mono<Action> actionMono = Mono.just(action)
.flatMap(actionService::create);
StepVerifier
@ -74,7 +146,7 @@ public class ActionServiceTest {
@WithUserDetails(value = "api_user")
public void invalidCreateActionNullName() {
Action action = new Action();
action.setPageId("randomPageId");
action.setPageId(testPage.getId());
ActionConfiguration actionConfiguration = new ActionConfiguration();
actionConfiguration.setHttpMethod(HttpMethod.GET);
action.setActionConfiguration(actionConfiguration);

View File

@ -72,13 +72,6 @@ public class ApplicationServiceTest {
.users(Set.of("api_user"))
.build();
Policy managePagePolicy = Policy.builder().permission(MANAGE_PAGES.getValue())
.users(Set.of("api_user"))
.build();
Policy readPagePolicy = Policy.builder().permission(READ_PAGES.getValue())
.users(Set.of("api_user"))
.build();
StepVerifier
.create(applicationMono)
.assertNext(application -> {

View File

@ -3,7 +3,10 @@ package com.appsmith.server.services;
import com.appsmith.external.models.ActionConfiguration;
import com.appsmith.external.models.Property;
import com.appsmith.external.plugins.PluginExecutor;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.domains.Action;
import com.appsmith.server.domains.Application;
import com.appsmith.server.domains.Page;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
@ -38,6 +41,12 @@ public class CurlImporterServiceTest {
@MockBean
PluginExecutor pluginExecutor;
@Autowired
ApplicationPageService applicationPageService;
@Autowired
PageService pageService;
@Before
public void setup() {
Mockito.when(this.pluginManager.getExtensions(Mockito.any(), Mockito.anyString()))
@ -82,8 +91,15 @@ public class CurlImporterServiceTest {
@Test
@WithUserDetails(value = "api_user")
public void importValidCurlCommand() {
// Set up the application & page for which this import curl action would be added
Application app = new Application();
app.setName("curlTest App");
Application application = applicationPageService.createApplication(app).block();
Page page = pageService.findById(application.getPages().get(0).getId(), AclPermission.MANAGE_PAGES).block();
String command = "curl -X GET http://localhost:8080/api/v1/actions?name=something -H 'Accept: */*' -H 'Accept-Encoding: gzip, deflate' -H 'Authorization: Basic YXBpX3VzZXI6OHVBQDsmbUI6Y252Tn57Iw==' -H 'Cache-Control: no-cache' -H 'Connection: keep-alive' -H 'Content-Type: application/json' -H 'Cookie: SESSION=97c5def4-4f72-45aa-96fe-e8a9f5ade0b5,SESSION=97c5def4-4f72-45aa-96fe-e8a9f5ade0b5; SESSION=' -H 'Host: localhost:8080' -H 'Postman-Token: 16e4b6bc-2c7a-4ab1-a127-bca382dfc0f0,a6655daa-db07-4c5e-aca3-3fd505bd230d' -H 'User-Agent: PostmanRuntime/7.20.1' -H 'cache-control: no-cache' -d '{someJson}'";
Mono<Action> action = curlImporterService.importAction(command, "pageId", "actionName");
Mono<Action> action = curlImporterService.importAction(command, page.getId(), "actionName");
StepVerifier
.create(action)
.assertNext(action1 -> {