Adding the policy hierarchy graph and the lateral policy graph

These graphs help us map policies that are inherited from the parent and also lateral policies that are assigned to the users given that the user has a particular permission. Currently, the hierarchy has been defined for org & application. Need to cascade it to more documents such as pages & actions.
This commit is contained in:
Arpit Mohan 2020-03-16 10:46:28 +05:30
parent a892ee90b5
commit 1f35bd6a07
25 changed files with 307 additions and 114 deletions

View File

@ -4,3 +4,4 @@ target/**
**/.idea
**/target
**/dist
*.iml

View File

@ -2,6 +2,7 @@ package com.appsmith.external.models;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@ -16,6 +17,7 @@ import java.util.Set;
@Setter
@ToString
@Builder
@EqualsAndHashCode
public class Policy implements Serializable {
String permission;

View File

@ -1,4 +1,4 @@
package com.appsmith.server.constants;
package com.appsmith.server.acl;
import java.util.Set;

View File

@ -0,0 +1,51 @@
package com.appsmith.server.acl;
import com.appsmith.server.domains.Action;
import com.appsmith.server.domains.Application;
import com.appsmith.server.domains.Organization;
import com.appsmith.server.domains.Page;
import lombok.Getter;
@Getter
public enum AclPermission {
// These are generic permissions created to make the transition to the new ACL format easy. They must be removed
CREATE("create", null),
READ("read", null),
UPDATE("update", null),
DELETE("delete", null),
MANAGE_ORGANIZATIONS("manage:organizations", Organization.class),
READ_ORGANIZATIONS("read:organizations", Organization.class),
ORGANIZATION_MANAGE_APPLICATIONS("manage:orgApplications", Organization.class),
ORGANIZATION_READ_APPLICATIONS("read:orgApplications", Organization.class),
ORGANIZATION_PUBLISH_APPLICATIONS("publish:orgApplications", Organization.class),
MANAGE_APPLICATIONS("manage:applications", Application.class),
READ_APPLICATIONS("read:applications", Application.class),
PUBLISH_APPLICATIONS("publish:applications", Application.class),
MANAGE_PAGES("manage:pages", Page.class),
READ_PAGES("read:pages", Page.class),
MANAGE_ACTIONS("manage:actions", Action.class),
READ_ACTIONS("read:actions", Action.class),
EXECUTE_ACTIONS("execute:actions", Action.class);
private String value;
private Class entity;
AclPermission(String value, Class entity) {
this.value = value;
this.entity = entity;
}
public static final AclPermission getPermissionByValue(String value, Class entity) {
for (AclPermission permission : values()) {
if (permission.getValue().equals(value) && permission.getEntity().equals(entity)) {
return permission;
}
}
return null;
}
}

View File

@ -0,0 +1,106 @@
package com.appsmith.server.acl;
import com.appsmith.external.models.Policy;
import com.appsmith.server.domains.User;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.DirectedMultigraph;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.EnumSet;
import java.util.Set;
import java.util.stream.Collectors;
import static com.appsmith.server.acl.AclPermission.MANAGE_ACTIONS;
import static com.appsmith.server.acl.AclPermission.MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.MANAGE_ORGANIZATIONS;
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.ORGANIZATION_PUBLISH_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.ORGANIZATION_READ_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.PUBLISH_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.READ_ACTIONS;
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;
@Getter
@Setter
@Slf4j
@Component
public class PolicyGenerator {
/**
* This graph defines the hierarchy of permissions from parent objects
*/
Graph<AclPermission, DefaultEdge> hierarchyGraph = new DirectedMultigraph<>(DefaultEdge.class);
/**
* This graph defines the permissions that must be given to a user given that they have another permission
* Eg: If the user is being given MANAGE_APPLICATION permission, they must also be given READ_APPLICATION permission
*/
Graph<AclPermission, DefaultEdge> lateralGraph = new DirectedMultigraph<>(DefaultEdge.class);
@PostConstruct
public void createPolicyGraph() {
EnumSet.allOf(AclPermission.class)
.forEach(permission -> {
hierarchyGraph.addVertex(permission);
lateralGraph.addVertex(permission);
});
createOrganizationPolicyGraph();
createApplicationPolicyGraph();
createPagePolicyGraph();
createActionPolicyGraph();
log.debug("Successfully created the createGraph & lateralGraph");
}
private void createOrganizationPolicyGraph() {
lateralGraph.addEdge(MANAGE_ORGANIZATIONS, READ_ORGANIZATIONS);
lateralGraph.addEdge(MANAGE_ORGANIZATIONS, ORGANIZATION_MANAGE_APPLICATIONS);
lateralGraph.addEdge(MANAGE_ORGANIZATIONS, ORGANIZATION_READ_APPLICATIONS);
lateralGraph.addEdge(MANAGE_ORGANIZATIONS, ORGANIZATION_PUBLISH_APPLICATIONS);
}
private void createApplicationPolicyGraph() {
hierarchyGraph.addEdge(ORGANIZATION_MANAGE_APPLICATIONS, MANAGE_APPLICATIONS);
hierarchyGraph.addEdge(ORGANIZATION_READ_APPLICATIONS, READ_APPLICATIONS);
hierarchyGraph.addEdge(ORGANIZATION_PUBLISH_APPLICATIONS, PUBLISH_APPLICATIONS);
// If the user is being given MANAGE_APPLICATION permission, they must also be given READ_APPLICATION perm
lateralGraph.addEdge(MANAGE_APPLICATIONS, READ_APPLICATIONS);
}
private void createActionPolicyGraph() {
hierarchyGraph.addEdge(MANAGE_PAGES, MANAGE_ACTIONS);
hierarchyGraph.addEdge(READ_PAGES, READ_ACTIONS);
lateralGraph.addEdge(MANAGE_PAGES, READ_PAGES);
}
private void createPagePolicyGraph() {
hierarchyGraph.addEdge(MANAGE_APPLICATIONS, MANAGE_PAGES);
hierarchyGraph.addEdge(READ_APPLICATIONS, READ_PAGES);
lateralGraph.addEdge(MANAGE_PAGES, READ_PAGES);
}
public Set<Policy> getLateralPoliciesForUser(AclPermission permission, User user) {
Set<DefaultEdge> lateralEdges = lateralGraph.outgoingEdgesOf(permission);
return lateralEdges.stream()
.map(lateralEdge -> {
AclPermission lateralPermission = lateralGraph.getEdgeTarget(lateralEdge);
return Policy.builder().permission(lateralPermission.getValue())
.users(Set.of(user.getUsername())).build();
})
.collect(Collectors.toSet());
}
}

View File

@ -1,6 +1,6 @@
package com.appsmith.server.authentication.handlers;
import com.appsmith.server.constants.AclConstants;
import com.appsmith.server.acl.AclConstants;
import com.appsmith.server.constants.Security;
import com.appsmith.server.domains.LoginSource;
import com.appsmith.server.domains.User;

View File

@ -1,13 +0,0 @@
package com.appsmith.server.constants;
import com.appsmith.external.models.BaseDomain;
import org.springframework.stereotype.Component;
@Component
public class AclComponent<T extends BaseDomain> {
public String getPermission(Object entity) {
System.out.println("In the getPermission");
return "read:applications";
}
}

View File

@ -1,34 +0,0 @@
package com.appsmith.server.constants;
import lombok.Getter;
@Getter
public enum AclPermission {
// These are generic permissions created to make the transition to the new ACL format easy. They must be removed
CREATE("create", null),
READ("read", null),
UPDATE("update", null),
DELETE("delete", null),
CREATE_ORGANIZATIONS("create:organizations", null),
READ_ORGANIZATIONS("read:organizations", null),
UPDATE_ORGANIZATIONS("update:organizations", null),
DELETE_ORGANIZATIONS("delete:organizations", null),
MANAGE_APPLICATIONS("manage:applications", null),
READ_APPLICATIONS("read:applications", MANAGE_APPLICATIONS),
CREATE_PAGES("create:pages", null),
READ_PAGES("read:pages", CREATE_PAGES),
UPDATE_PAGES("update:pages", null),
DELETE_PAGES("delete:pages", null);
private String value;
private AclPermission parent;
AclPermission(String value, AclPermission parent) {
this.value = value;
}
}

View File

@ -1,6 +1,6 @@
package com.appsmith.server.repositories;
import com.appsmith.server.constants.AclPermission;
import com.appsmith.server.acl.AclPermission;
import reactor.core.publisher.Mono;
public interface AppsmithRepository<T> {

View File

@ -2,7 +2,7 @@ package com.appsmith.server.repositories;
import com.appsmith.external.models.BaseDomain;
import com.appsmith.external.models.QBaseDomain;
import com.appsmith.server.constants.AclPermission;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.User;
import com.appsmith.server.exceptions.AppsmithError;
@ -54,13 +54,13 @@ public abstract class BaseAppsmithRepositoryImpl<T extends BaseDomain> {
public static final Criteria userAcl(User user, AclPermission permission) {
log.debug("Going to add userAcl for user: {} and permission: {}", user.getUsername(), permission.getValue());
Criteria userCriteria = Criteria.where("policies")
Criteria userCriteria = Criteria.where(fieldName(QBaseDomain.baseDomain.policies))
.elemMatch(Criteria.where("users").all(user.getUsername())
.and("permission").is(permission.getValue())
);
log.debug("Got the userCriteria: {}", userCriteria.getCriteriaObject());
Criteria groupCriteria = Criteria.where("policies")
Criteria groupCriteria = Criteria.where(fieldName(QBaseDomain.baseDomain.policies))
.elemMatch(Criteria.where("groups").all(user.getGroupIds())
.and("permission").is(permission.getValue()));

View File

@ -1,7 +1,7 @@
package com.appsmith.server.repositories;
import com.appsmith.external.models.BaseDomain;
import com.appsmith.server.constants.AclPermission;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.User;
import lombok.NonNull;

View File

@ -1,6 +1,6 @@
package com.appsmith.server.repositories;
import com.appsmith.server.constants.AclPermission;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.domains.Application;
import reactor.core.publisher.Mono;

View File

@ -1,6 +1,6 @@
package com.appsmith.server.repositories;
import com.appsmith.server.constants.AclPermission;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.domains.Application;
import com.appsmith.server.domains.QApplication;
import com.appsmith.server.domains.User;

View File

@ -1,7 +1,8 @@
package com.appsmith.server.services;
import com.appsmith.external.models.Policy;
import com.appsmith.server.constants.AclPermission;
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.Application;
@ -13,15 +14,20 @@ import com.appsmith.server.domains.User;
import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException;
import lombok.extern.slf4j.Slf4j;
import org.jgrapht.graph.DefaultEdge;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.appsmith.server.acl.AclPermission.ORGANIZATION_MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.ORGANIZATION_READ_APPLICATIONS;
@Slf4j
@Service
public class ApplicationPageServiceImpl implements ApplicationPageService {
@ -31,17 +37,20 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
private final OrganizationService organizationService;
private final AnalyticsService analyticsService;
private final PolicyGenerator policyGenerator;
public ApplicationPageServiceImpl(ApplicationService applicationService,
PageService pageService,
SessionUserService sessionUserService,
OrganizationService organizationService,
AnalyticsService analyticsService) {
AnalyticsService analyticsService,
PolicyGenerator policyGenerator) {
this.applicationService = applicationService;
this.pageService = pageService;
this.sessionUserService = sessionUserService;
this.organizationService = organizationService;
this.analyticsService = analyticsService;
this.policyGenerator = policyGenerator;
}
public Mono<Page> createPage(Page page) {
@ -62,7 +71,7 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
page.setLayouts(layoutList);
}
Mono<Application> applicationMono = applicationService.findById(page.getApplicationId(), AclPermission.CREATE_PAGES)
Mono<Application> applicationMono = applicationService.findById(page.getApplicationId(), AclPermission.MANAGE_PAGES)
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.APPLICATION_ID, page.getApplicationId())));
return applicationMono
@ -199,7 +208,7 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
.flatMap(user -> {
String orgId = user.getCurrentOrganizationId();
Mono<Organization> orgMono = organizationService.findById(orgId, AclPermission.MANAGE_APPLICATIONS)
Mono<Organization> orgMono = organizationService.findById(orgId, ORGANIZATION_MANAGE_APPLICATIONS)
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.ORGANIZATION, orgId)));
return orgMono.map(org -> {
@ -208,18 +217,36 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
// to the new application that we are creating.
Set<Policy> policySet = org.getPolicies().stream()
.filter(policy ->
policy.getPermission().equals(AclPermission.READ_APPLICATIONS.getValue()) ||
policy.getPermission().equals(AclPermission.MANAGE_APPLICATIONS.getValue())
policy.getPermission().equals(ORGANIZATION_MANAGE_APPLICATIONS.getValue()) ||
policy.getPermission().equals(ORGANIZATION_READ_APPLICATIONS.getValue())
).collect(Collectors.toSet());
Set<String> users = policySet.stream()
.map(policy -> policy.getUsers())
Set<Policy> documentPolicies = policySet.stream()
.map(policy -> {
AclPermission aclPermission = AclPermission
.getPermissionByValue(policy.getPermission(), Organization.class);
// Check the hierarchy graph to derive child permissions that must be given to this
// document
Set<Policy> childPolicySet = new HashSet<>();
Set<DefaultEdge> edges = policyGenerator.getHierarchyGraph()
.outgoingEdgesOf(aclPermission);
for (DefaultEdge edge: edges) {
AclPermission childPermission = policyGenerator.getHierarchyGraph().getEdgeTarget(edge);
childPolicySet.add(Policy.builder().permission(childPermission.getValue())
.users(policy.getUsers()).build());
// Get the lateral permissions that must be applied given the child permission
// This is applied at a user level and not from the parent object. Hence only the
// current user gets these permissions
childPolicySet.addAll(policyGenerator.getLateralPoliciesForUser(childPermission, user));
}
childPolicySet.addAll(policyGenerator.getLateralPoliciesForUser(aclPermission, user));
return childPolicySet;
})
.flatMap(Collection::stream)
.collect(Collectors.toSet());
policySet.add(Policy.builder()
.permission(AclPermission.CREATE_PAGES.getValue())
.users(Set.of(user.getUsername())).build()
);
application.setPolicies(policySet);
application.setPolicies(documentPolicies);
return application;
});
});

View File

@ -1,6 +1,6 @@
package com.appsmith.server.services;
import com.appsmith.server.constants.AclPermission;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.domains.Application;
import reactor.core.publisher.Mono;

View File

@ -1,6 +1,6 @@
package com.appsmith.server.services;
import com.appsmith.server.constants.AclPermission;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.constants.AnalyticsEvents;
import com.appsmith.server.constants.Entity;
import com.appsmith.server.constants.FieldName;
@ -13,15 +13,11 @@ import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.repositories.ActionRepository;
import com.appsmith.server.repositories.ApplicationRepository;
import com.appsmith.server.repositories.PageRepository;
import com.mongodb.DBObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import reactor.core.publisher.Flux;
@ -31,7 +27,6 @@ import reactor.core.scheduler.Scheduler;
import javax.validation.Validator;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Slf4j

View File

@ -1,7 +1,6 @@
package com.appsmith.server.services;
import com.appsmith.external.models.BaseDomain;
import com.appsmith.server.constants.AclPermission;
import com.appsmith.server.constants.AnalyticsEvents;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.exceptions.AppsmithError;

View File

@ -1,6 +1,6 @@
package com.appsmith.server.services;
import com.appsmith.server.constants.AclConstants;
import com.appsmith.server.acl.AclConstants;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.Group;
import com.appsmith.server.repositories.GroupRepository;

View File

@ -1,6 +1,6 @@
package com.appsmith.server.services;
import com.appsmith.server.constants.AclPermission;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.domains.Organization;
import com.appsmith.server.domains.User;
import reactor.core.publisher.Mono;

View File

@ -1,7 +1,8 @@
package com.appsmith.server.services;
import com.appsmith.external.models.Policy;
import com.appsmith.server.constants.AclPermission;
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.Organization;
@ -15,6 +16,7 @@ import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.repositories.OrganizationRepository;
import com.appsmith.server.repositories.PluginRepository;
import lombok.extern.slf4j.Slf4j;
import org.jgrapht.graph.DefaultEdge;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.convert.MongoConverter;
@ -26,11 +28,14 @@ import reactor.core.scheduler.Scheduler;
import javax.validation.Validator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.appsmith.server.acl.AclPermission.MANAGE_ORGANIZATIONS;
@Slf4j
@Service
public class OrganizationServiceImpl extends BaseService<OrganizationRepository, Organization, String> implements OrganizationService {
@ -41,6 +46,7 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
private final PluginRepository pluginRepository;
private final SessionUserService sessionUserService;
private final UserOrganizationService userOrganizationService;
private final PolicyGenerator policyGenerator;
@Autowired
public OrganizationServiceImpl(Scheduler scheduler,
@ -53,7 +59,8 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
GroupService groupService,
PluginRepository pluginRepository,
SessionUserService sessionUserService,
UserOrganizationService userOrganizationService) {
UserOrganizationService userOrganizationService,
PolicyGenerator policyGenerator) {
super(scheduler, validator, mongoConverter, reactiveMongoTemplate, repository, analyticsService);
this.repository = repository;
this.settingService = settingService;
@ -61,6 +68,7 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
this.pluginRepository = pluginRepository;
this.sessionUserService = sessionUserService;
this.userOrganizationService = userOrganizationService;
this.policyGenerator = policyGenerator;
}
@Override
@ -81,41 +89,62 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
return repository.findByName(name);
}
private Set<Policy> crudAppPolicy(User user) {
Policy readAppPolicy = Policy.builder().permission(AclPermission.READ_APPLICATIONS.getValue())
.users(Set.of(user.getUsername()))
.build();
Policy manageAppPolicy = Policy.builder().permission(AclPermission.MANAGE_APPLICATIONS.getValue())
.users(Set.of(user.getUsername()))
.build();
return Set.of(manageAppPolicy, readAppPolicy);
}
// private Set<Policy> crudAppPolicy(User user) {
// Policy readAppPolicy = Policy.builder().permission(AclPermission.READ_APPLICATIONS.getValue())
// .users(Set.of(user.getUsername()))
// .build();
//
// Policy manageAppPolicy = Policy.builder().permission(AclPermission.MANAGE_APPLICATIONS.getValue())
// .users(Set.of(user.getUsername()))
// .build();
//
// return Set.of(manageAppPolicy, readAppPolicy);
// }
private Set<Policy> crudOrgPolicy(User user) {
Policy readOrgPolicy = Policy.builder().permission(AclPermission.READ_ORGANIZATIONS.getValue())
.users(Set.of(user.getUsername()))
.build();
Set<Policy> policySet = user.getPolicies().stream()
.filter(policy ->
policy.getPermission().equals(MANAGE_ORGANIZATIONS.getValue())
).collect(Collectors.toSet());
Policy updateOrgPolicy = Policy.builder().permission(AclPermission.UPDATE_ORGANIZATIONS.getValue())
.users(Set.of(user.getUsername()))
.build();
Set<Policy> documentPolicies = policySet.stream()
.map(policy -> {
AclPermission aclPermission = AclPermission
.getPermissionByValue(policy.getPermission(), Organization.class);
// Check the hierarchy graph to derive child permissions that must be given to this
// document
Set<Policy> childPolicySet = new HashSet<>();
Set<DefaultEdge> edges = policyGenerator.getHierarchyGraph()
.outgoingEdgesOf(aclPermission);
for (DefaultEdge edge : edges) {
AclPermission childPermission = policyGenerator.getHierarchyGraph().getEdgeTarget(edge);
childPolicySet.add(Policy.builder().permission(childPermission.getValue())
.users(policy.getUsers()).build());
Policy deleteOrgPolicy = Policy.builder().permission(AclPermission.DELETE_ORGANIZATIONS.getValue())
// Get the lateral permissions that must be applied given the child permission
// This is applied at a user level and not from the parent object. Hence only the
// current user gets these permissions
childPolicySet.addAll(policyGenerator.getLateralPoliciesForUser(childPermission, user));
}
childPolicySet.addAll(policyGenerator.getLateralPoliciesForUser(aclPermission, user));
return childPolicySet;
}).flatMap(Collection::stream)
.collect(Collectors.toSet());
Policy manageOrgPolicy = Policy.builder().permission(MANAGE_ORGANIZATIONS.getValue())
.users(Set.of(user.getUsername()))
.build();
return Set.of(readOrgPolicy, updateOrgPolicy,deleteOrgPolicy);
documentPolicies.add(manageOrgPolicy);
return documentPolicies;
}
private Set<Policy> adminPoliciesForOrganization(User user) {
Set<Policy> crudAppPolicies = crudAppPolicy(user);
Set<Policy> crudOrgPolicies = crudOrgPolicy(user);
Set<Policy> adminPolicies = new HashSet<>();
adminPolicies.addAll(crudOrgPolicies);
adminPolicies.addAll(crudAppPolicies);
return adminPolicies;
}
@ -138,7 +167,7 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
}
// Set the admin policies for this organization & user
organization.setPolicies(adminPoliciesForOrganization(user));
organization.setPolicies(crudOrgPolicy(user));
Mono<Organization> organizationMono = Mono.just(organization)
.flatMap(this::validateObject)
@ -219,7 +248,7 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
@Override
public Mono<Organization> update(String id, Organization resource) {
return repository.updateById(id, resource, AclPermission.UPDATE_ORGANIZATIONS)
return repository.updateById(id, resource, MANAGE_ORGANIZATIONS)
.flatMap(updatedObj -> analyticsService.sendEvent(AnalyticsEvents.UPDATE + "_" + updatedObj.getClass().getSimpleName().toUpperCase(), updatedObj));
}

View File

@ -1,6 +1,6 @@
package com.appsmith.server.services;
import com.appsmith.server.constants.AclConstants;
import com.appsmith.server.acl.AclConstants;
import com.appsmith.server.domains.Group;
import com.appsmith.server.domains.Organization;
import com.appsmith.server.domains.User;

View File

@ -1,6 +1,6 @@
package com.appsmith.server.services;
import com.appsmith.server.constants.AclPermission;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.domains.Organization;
import com.appsmith.server.domains.User;
import com.appsmith.server.exceptions.AppsmithError;

View File

@ -1,7 +1,7 @@
package com.appsmith.server.configurations;
import com.appsmith.external.models.Policy;
import com.appsmith.server.constants.AclPermission;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.domains.Application;
import com.appsmith.server.domains.Organization;
import com.appsmith.server.domains.OrganizationPlugin;
@ -23,9 +23,14 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.appsmith.server.acl.AclPermission.MANAGE_ORGANIZATIONS;
import static com.appsmith.server.acl.AclPermission.ORGANIZATION_MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.READ_APPLICATIONS;
@Slf4j
@Configuration
public class SeedMongoData {
@ -38,20 +43,24 @@ public class SeedMongoData {
PluginRepository pluginRepository) {
log.info("Seeding the data");
Policy readAppPolicy = Policy.builder().permission(AclPermission.READ_APPLICATIONS.getValue())
Policy readAppPolicy = Policy.builder().permission(READ_APPLICATIONS.getValue())
.users(Set.of("api_user"))
.build();
Policy manageAppPolicy = Policy.builder().permission(AclPermission.MANAGE_APPLICATIONS.getValue())
Policy manageAppPolicy = Policy.builder().permission(ORGANIZATION_MANAGE_APPLICATIONS.getValue())
.users(Set.of("api_user"))
.build();
Policy manageOrgPolicy = Policy.builder().permission(MANAGE_ORGANIZATIONS.getValue())
.users(Set.of("api_user"))
.build();
Object[][] userData = {
{"user test", "usertest@usertest.com", UserState.ACTIVATED},
{"api_user", "api_user", UserState.ACTIVATED},
{"user test", "usertest@usertest.com", UserState.ACTIVATED, new HashSet<>()},
{"api_user", "api_user", UserState.ACTIVATED, Set.of(manageOrgPolicy)},
};
Object[][] orgData = {
{"Spring Test Organization", "appsmith-spring-test.com", "appsmith.com", Set.of(readAppPolicy, manageAppPolicy)}
{"Spring Test Organization", "appsmith-spring-test.com", "appsmith.com", Set.of(manageAppPolicy)}
};
Object[][] appData = {
@ -107,6 +116,7 @@ public class SeedMongoData {
user.setName((String) array[0]);
user.setEmail((String) array[1]);
user.setState((UserState) array[2]);
user.setPolicies((Set<Policy>) array[3]);
user.setCurrentOrganizationId(orgId);
return user;
})
@ -122,7 +132,7 @@ public class SeedMongoData {
return app;
}).flatMap(applicationRepository::save)
// Query the seed data to get the applicationId (required for page creation)
).then(applicationRepository.findByName((String) appData[0][0], AclPermission.READ_APPLICATIONS))
).then(applicationRepository.findByName((String) appData[0][0], READ_APPLICATIONS))
.map(application -> application.getId())
.flatMapMany(appId -> Flux.just(pageData)
// Seed the page data into the DB

View File

@ -1,5 +1,6 @@
package com.appsmith.server.services;
import com.appsmith.external.models.Policy;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.Application;
import com.appsmith.server.exceptions.AppsmithError;
@ -15,6 +16,11 @@ import org.springframework.test.context.junit4.SpringRunner;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.util.Set;
import static com.appsmith.server.acl.AclPermission.MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.ORGANIZATION_MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.READ_APPLICATIONS;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@ -49,6 +55,13 @@ public class ApplicationServiceTest {
testApplication.setName("ApplicationServiceTest TestApp");
Mono<Application> applicationMono = applicationPageService.createApplication(testApplication);
Policy manageAppPolicy = Policy.builder().permission(MANAGE_APPLICATIONS.getValue())
.users(Set.of("api_user"))
.build();
Policy readAppPolicy = Policy.builder().permission(READ_APPLICATIONS.getValue())
.users(Set.of("api_user"))
.build();
StepVerifier
.create(applicationMono)
.assertNext(application -> {
@ -56,6 +69,7 @@ public class ApplicationServiceTest {
assertThat(application.getId()).isNotNull();
assertThat(application.getName().equals("ApplicationServiceTest TestApp"));
assertThat(application.getPolicies()).isNotEmpty();
assertThat(application.getPolicies()).containsAll(Set.of(manageAppPolicy, readAppPolicy));
})
.verifyComplete();
}

View File

@ -1,7 +1,6 @@
package com.appsmith.server.services;
import com.appsmith.external.models.Policy;
import com.appsmith.server.constants.AclPermission;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.Organization;
import com.appsmith.server.exceptions.AppsmithError;
@ -20,6 +19,8 @@ import reactor.test.StepVerifier;
import java.util.Set;
import static com.appsmith.server.acl.AclPermission.MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.ORGANIZATION_MANAGE_APPLICATIONS;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringJUnit4ClassRunner.class)
@ -66,12 +67,17 @@ public class OrganizationServiceTest {
@Test
@WithUserDetails(value = "api_user")
public void validCreateOrganizationTest() {
Policy manageOrgAppPolicy = Policy.builder().permission(ORGANIZATION_MANAGE_APPLICATIONS.getValue())
.users(Set.of("api_user"))
.build();
Mono<Organization> organizationResponse = organizationService.create(organization)
.switchIfEmpty(Mono.error(new Exception("create is returning empty!!")));
StepVerifier.create(organizationResponse)
.assertNext(organization1 -> {
assertThat(organization1.getName()).isEqualTo("Test Name");
assertThat(organization1.getPolicies()).isNotEmpty();
assertThat(organization1.getPolicies()).containsAll(Set.of(manageOrgAppPolicy));
})
.verifyComplete();
}