diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 5c913eea5a..62aee4b201 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -25,7 +25,9 @@ include::content/docs/variables.adoc-include[] [[v1.10.0]] == 1.10.0 (TBD) -icon:check[] Core: The OrientDB database as been updated to version 3.2.10. +icon:plus[] Core: The OrientDB database as been updated to version 3.2.10. + +icon:plus[] Rest: The new endpoints `/api/v2/.../rolePermissions` allow getting, granting and revoking permissions on entities for multiple roles in a single request. [[v1.9.3]] == 1.9.3 (22.09.2022) diff --git a/common/src/main/resources/i18n/translations_de.properties b/common/src/main/resources/i18n/translations_de.properties index c2cfe9d93a..ee6e9bf3c3 100644 --- a/common/src/main/resources/i18n/translations_de.properties +++ b/common/src/main/resources/i18n/translations_de.properties @@ -114,6 +114,7 @@ role_missing_parentgroup_field=Es wurde keine Gruppe für die Rolle angegeben. D role_updated_permission=Berechtigung für Rolle {0} wurde aktualisiert. role_permission_path_missing=Es wurde kein Pfad angegeben. role_error_permission_name_unknown=Name der angegebenen Berechtigung "{0}" ist unbekannt. +role_reference_uuid_or_name_missing=Es wurde kein Name oder Uuid für die Rolle angegeben. project_deleted=Projekt "{0}" wurde gelöscht. project_version_purge_enqueued=Der Auftrag für die Projektversionsbereinigung wurde eingereiht. diff --git a/common/src/main/resources/i18n/translations_en.properties b/common/src/main/resources/i18n/translations_en.properties index 4b8d60f7ed..b13ada8c91 100644 --- a/common/src/main/resources/i18n/translations_en.properties +++ b/common/src/main/resources/i18n/translations_en.properties @@ -112,7 +112,8 @@ role_conflicting_name=Role name is conflicting with an existing role. role_missing_parentgroup_field=No parent group was specified for the role. Please set a parent group uuid. role_updated_permission=Permission for role {0} updated. role_permission_path_missing=No path was specified. -role_error_permission_name_unknown=Found permission name "{0}" is unknown. +role_error_permission_name_unknown=Found permission name "{0}" is unknown. +role_reference_uuid_or_name_missing=The role reference must contain either name or uuid. project_deleted=Project "{0}" was deleted. project_version_purge_enqueued=Project version purge job was queued. diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingEndpoint.java new file mode 100644 index 0000000000..6b5065fcb3 --- /dev/null +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingEndpoint.java @@ -0,0 +1,81 @@ +package com.gentics.mesh.core.endpoint; + +import static com.gentics.mesh.core.rest.MeshEvent.ROLE_PERMISSIONS_CHANGED; +import static com.gentics.mesh.http.HttpConstants.APPLICATION_JSON; +import static io.netty.handler.codec.http.HttpResponseStatus.OK; +import static io.vertx.core.http.HttpMethod.DELETE; +import static io.vertx.core.http.HttpMethod.GET; +import static io.vertx.core.http.HttpMethod.POST; + +import com.gentics.mesh.auth.MeshAuthChainImpl; +import com.gentics.mesh.context.InternalActionContext; +import com.gentics.mesh.core.endpoint.handler.AbstractCrudHandler; +import com.gentics.mesh.rest.InternalEndpointRoute; +import com.gentics.mesh.router.route.AbstractInternalEndpoint; + +/** + * Abstract endpoint implementation with methods that add routes for getting/granting/revoking role permissions + */ +public abstract class RolePermissionHandlingEndpoint extends AbstractInternalEndpoint { + + protected RolePermissionHandlingEndpoint(String basePath, MeshAuthChainImpl chain) { + super(basePath, chain); + } + + /** + * Add role permission handler + * @param uuidParameterName name of the uuid parameter (e.g. "groupUuid") + * @param uuidParameterExample example of the uuid parameter + * @param typeDescription description of the object type (e.g. "group") + * @param crudHandler crud handler + * @param includePublishPermissions true to include the publish permissions into the example + */ + protected void addRolePermissionHandler(String uuidParameterName, String uuidParameterExample, String typeDescription, + AbstractCrudHandler crudHandler, boolean includePublishPermissions) { + String path = "/:" + uuidParameterName + "/rolePermissions"; + InternalEndpointRoute readPermissionsEndpoint = createRoute(); + readPermissionsEndpoint.path(path); + readPermissionsEndpoint.addUriParameter(uuidParameterName, "Uuid of the " + typeDescription, uuidParameterExample); + readPermissionsEndpoint.method(GET); + readPermissionsEndpoint.description("Get the permissions on the " + typeDescription + " for all roles."); + readPermissionsEndpoint.produces(APPLICATION_JSON); + readPermissionsEndpoint.exampleResponse(OK, roleExamples.getObjectPermissionResponse(includePublishPermissions), "Loaded permissions."); + readPermissionsEndpoint.blockingHandler(rc -> { + InternalActionContext ac = wrap(rc); + String uuid = rc.request().getParam(uuidParameterName); + crudHandler.handleReadPermissions(ac, uuid); + }, false); + + InternalEndpointRoute grantPermissionsEndpoint = createRoute(); + grantPermissionsEndpoint.path(path); + grantPermissionsEndpoint.addUriParameter(uuidParameterName, "Uuid of the " + typeDescription, uuidParameterExample); + grantPermissionsEndpoint.method(POST); + grantPermissionsEndpoint.description("Grant permissions on the " + typeDescription + " to multiple roles."); + grantPermissionsEndpoint.consumes(APPLICATION_JSON); + grantPermissionsEndpoint.produces(APPLICATION_JSON); + grantPermissionsEndpoint.exampleRequest(roleExamples.getObjectPermissionGrantRequest(includePublishPermissions)); + grantPermissionsEndpoint.exampleResponse(OK, roleExamples.getObjectPermissionResponse(includePublishPermissions), "Updated permissions."); + grantPermissionsEndpoint.events(ROLE_PERMISSIONS_CHANGED); + grantPermissionsEndpoint.blockingHandler(rc -> { + InternalActionContext ac = wrap(rc); + String uuid = rc.request().getParam(uuidParameterName); + crudHandler.handleGrantPermissions(ac, uuid); + }); + + InternalEndpointRoute revokePermissionsEndpoint = createRoute(); + revokePermissionsEndpoint.path(path); + revokePermissionsEndpoint.addUriParameter(uuidParameterName, "Uuid of the " + typeDescription, uuidParameterExample); + revokePermissionsEndpoint.method(DELETE); + revokePermissionsEndpoint.description("Revoke permissions on the " + typeDescription + " from multiple roles."); + revokePermissionsEndpoint.consumes(APPLICATION_JSON); + revokePermissionsEndpoint.produces(APPLICATION_JSON); + revokePermissionsEndpoint.exampleRequest(roleExamples.getObjectPermissionRevokeRequest(includePublishPermissions)); + revokePermissionsEndpoint.exampleResponse(OK, roleExamples.getObjectPermissionResponse(includePublishPermissions), "Updated permissions."); + revokePermissionsEndpoint.events(ROLE_PERMISSIONS_CHANGED); + revokePermissionsEndpoint.blockingHandler(rc -> { + InternalActionContext ac = wrap(rc); + String uuid = rc.request().getParam(uuidParameterName); + crudHandler.handleRevokePermissions(ac, uuid); + }); + } +} diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingProjectEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingProjectEndpoint.java new file mode 100644 index 0000000000..bdd6ffe2d2 --- /dev/null +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/RolePermissionHandlingProjectEndpoint.java @@ -0,0 +1,83 @@ +package com.gentics.mesh.core.endpoint; + +import static com.gentics.mesh.core.rest.MeshEvent.ROLE_PERMISSIONS_CHANGED; +import static com.gentics.mesh.http.HttpConstants.APPLICATION_JSON; +import static io.netty.handler.codec.http.HttpResponseStatus.OK; +import static io.vertx.core.http.HttpMethod.DELETE; +import static io.vertx.core.http.HttpMethod.GET; +import static io.vertx.core.http.HttpMethod.POST; + +import com.gentics.mesh.auth.MeshAuthChainImpl; +import com.gentics.mesh.cli.BootstrapInitializer; +import com.gentics.mesh.context.InternalActionContext; +import com.gentics.mesh.core.endpoint.handler.AbstractCrudHandler; +import com.gentics.mesh.rest.InternalEndpointRoute; +import com.gentics.mesh.router.route.AbstractProjectEndpoint; + +/** + * Abstract endpoint implementation with methods that add routes for getting/granting/revoking role permissions + */ +public abstract class RolePermissionHandlingProjectEndpoint extends AbstractProjectEndpoint { + + protected RolePermissionHandlingProjectEndpoint(String basePath, MeshAuthChainImpl chain, + BootstrapInitializer boot) { + super(basePath, chain, boot); + } + + /** + * Add role permission handler + * @param uuidParameterName name of the uuid parameter (e.g. "groupUuid") + * @param uuidParameterExample example of the uuid parameter + * @param typeDescription description of the object type (e.g. "group") + * @param crudHandler crud handler + * @param includePublishPermissions true to include the publish permissions into the example + */ + protected void addRolePermissionHandler(String uuidParameterName, String uuidParameterExample, String typeDescription, + AbstractCrudHandler crudHandler, boolean includePublishPermissions) { + String path = "/:" + uuidParameterName + "/rolePermissions"; + InternalEndpointRoute readPermissionsEndpoint = createRoute(); + readPermissionsEndpoint.path(path); + readPermissionsEndpoint.addUriParameter(uuidParameterName, "Uuid of the " + typeDescription, uuidParameterExample); + readPermissionsEndpoint.method(GET); + readPermissionsEndpoint.description("Get the permissions on the " + typeDescription + " for all roles."); + readPermissionsEndpoint.produces(APPLICATION_JSON); + readPermissionsEndpoint.exampleResponse(OK, roleExamples.getObjectPermissionResponse(includePublishPermissions), "Loaded permissions."); + readPermissionsEndpoint.blockingHandler(rc -> { + InternalActionContext ac = wrap(rc); + String uuid = rc.request().getParam(uuidParameterName); + crudHandler.handleReadPermissions(ac, uuid); + }, false); + + InternalEndpointRoute grantPermissionsEndpoint = createRoute(); + grantPermissionsEndpoint.path(path); + grantPermissionsEndpoint.addUriParameter(uuidParameterName, "Uuid of the " + typeDescription, uuidParameterExample); + grantPermissionsEndpoint.method(POST); + grantPermissionsEndpoint.description("Grant permissions on the " + typeDescription + " to multiple roles."); + grantPermissionsEndpoint.consumes(APPLICATION_JSON); + grantPermissionsEndpoint.produces(APPLICATION_JSON); + grantPermissionsEndpoint.exampleRequest(roleExamples.getObjectPermissionGrantRequest(includePublishPermissions)); + grantPermissionsEndpoint.exampleResponse(OK, roleExamples.getObjectPermissionResponse(includePublishPermissions), "Updated permissions."); + grantPermissionsEndpoint.events(ROLE_PERMISSIONS_CHANGED); + grantPermissionsEndpoint.blockingHandler(rc -> { + InternalActionContext ac = wrap(rc); + String uuid = rc.request().getParam(uuidParameterName); + crudHandler.handleGrantPermissions(ac, uuid); + }); + + InternalEndpointRoute revokePermissionsEndpoint = createRoute(); + revokePermissionsEndpoint.path(path); + revokePermissionsEndpoint.addUriParameter(uuidParameterName, "Uuid of the " + typeDescription, uuidParameterExample); + revokePermissionsEndpoint.method(DELETE); + revokePermissionsEndpoint.description("Revoke permissions on the " + typeDescription + " from multiple roles."); + revokePermissionsEndpoint.consumes(APPLICATION_JSON); + revokePermissionsEndpoint.produces(APPLICATION_JSON); + revokePermissionsEndpoint.exampleRequest(roleExamples.getObjectPermissionRevokeRequest(includePublishPermissions)); + revokePermissionsEndpoint.exampleResponse(OK, roleExamples.getObjectPermissionResponse(includePublishPermissions), "Updated permissions."); + revokePermissionsEndpoint.events(ROLE_PERMISSIONS_CHANGED); + revokePermissionsEndpoint.blockingHandler(rc -> { + InternalActionContext ac = wrap(rc); + String uuid = rc.request().getParam(uuidParameterName); + crudHandler.handleRevokePermissions(ac, uuid); + }); + } +} diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/branch/BranchEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/branch/BranchEndpoint.java index 73a57520c2..08ff0d75b2 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/branch/BranchEndpoint.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/branch/BranchEndpoint.java @@ -28,15 +28,15 @@ import com.gentics.mesh.auth.MeshAuthChainImpl; import com.gentics.mesh.cli.BootstrapInitializer; import com.gentics.mesh.context.InternalActionContext; +import com.gentics.mesh.core.endpoint.RolePermissionHandlingProjectEndpoint; import com.gentics.mesh.parameter.impl.GenericParametersImpl; import com.gentics.mesh.parameter.impl.PagingParametersImpl; import com.gentics.mesh.rest.InternalEndpointRoute; -import com.gentics.mesh.router.route.AbstractProjectEndpoint; /** * Verticle for REST endpoints to manage branches. */ -public class BranchEndpoint extends AbstractProjectEndpoint { +public class BranchEndpoint extends RolePermissionHandlingProjectEndpoint { private BranchCrudHandler crudHandler; @@ -67,6 +67,7 @@ public void registerEndPoints() { addNodeMigrationHandler(); addMicronodeMigrationHandler(); addTagsHandler(); + addRolePermissionHandler("branchUuid", BRANCH_UUID, "branch", crudHandler, false); } private void addMicroschemaInfoHandler() { diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/group/GroupEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/group/GroupEndpoint.java index 7928b8d4ff..c64a85b34b 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/group/GroupEndpoint.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/group/GroupEndpoint.java @@ -24,16 +24,16 @@ import com.gentics.mesh.auth.MeshAuthChainImpl; import com.gentics.mesh.context.InternalActionContext; +import com.gentics.mesh.core.endpoint.RolePermissionHandlingEndpoint; import com.gentics.mesh.parameter.impl.GenericParametersImpl; import com.gentics.mesh.parameter.impl.PagingParametersImpl; import com.gentics.mesh.parameter.impl.RolePermissionParametersImpl; import com.gentics.mesh.rest.InternalEndpointRoute; -import com.gentics.mesh.router.route.AbstractInternalEndpoint; /** - * Endpoint defintion for /api/v1/groups + * Endpoint definition for /api/v1/groups */ -public class GroupEndpoint extends AbstractInternalEndpoint { +public class GroupEndpoint extends RolePermissionHandlingEndpoint { private GroupCrudHandler crudHandler; @@ -63,6 +63,7 @@ public void registerEndPoints() { addReadHandler(); addUpdateHandler(); addDeleteHandler(); + addRolePermissionHandler("groupUuid", GROUP_CLIENT_UUID, "group", crudHandler, false); } private void addGroupRoleHandlers() { diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/handler/AbstractCrudHandler.java b/core/src/main/java/com/gentics/mesh/core/endpoint/handler/AbstractCrudHandler.java index 2eacb3c404..ffcc4d4e33 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/handler/AbstractCrudHandler.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/handler/AbstractCrudHandler.java @@ -2,19 +2,42 @@ import static com.gentics.mesh.core.action.DAOActionContext.context; import static com.gentics.mesh.core.data.perm.InternalPermission.READ_PERM; +import static com.gentics.mesh.core.data.perm.InternalPermission.UPDATE_PERM; import static com.gentics.mesh.core.rest.error.Errors.error; +import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; +import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; +import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static org.apache.commons.lang3.StringUtils.isEmpty; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; + import com.gentics.mesh.annotation.Getter; import com.gentics.mesh.context.InternalActionContext; import com.gentics.mesh.context.impl.InternalRoutingActionContextImpl; import com.gentics.mesh.core.action.DAOActions; import com.gentics.mesh.core.data.HibCoreElement; +import com.gentics.mesh.core.data.dao.RoleDao; +import com.gentics.mesh.core.data.dao.UserDao; +import com.gentics.mesh.core.data.perm.InternalPermission; +import com.gentics.mesh.core.data.role.HibRole; +import com.gentics.mesh.core.data.user.HibUser; import com.gentics.mesh.core.db.Database; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.common.RestModel; +import com.gentics.mesh.core.rest.role.RoleReference; import com.gentics.mesh.core.verticle.handler.HandlerUtilities; import com.gentics.mesh.core.verticle.handler.WriteLock; +import com.gentics.mesh.parameter.impl.PagingParametersImpl; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; @@ -103,4 +126,195 @@ public Handler getUuidHandler(String i18nNotFoundMessage) { return handler; } + /** + * Handle request to read permissions for all roles + * @param ac action context + * @param uuid entity uuid + */ + public void handleReadPermissions(InternalActionContext ac, String uuid) { + validateParameter(uuid, "uuid"); + utils.syncTx(ac, tx -> { + RoleDao roleDao = tx.roleDao(); + T object = crudActions().loadByUuid(context(tx, ac), uuid, READ_PERM, true); + Set allRoles = roleDao.findAll(ac, new PagingParametersImpl().setPerPage(Long.MAX_VALUE)).stream().collect(Collectors.toSet()); + + Map> permissions = roleDao.getPermissions(allRoles, object); + permissions.values().removeIf(Set::isEmpty); + + ObjectPermissionResponse response = new ObjectPermissionResponse(); + permissions.entrySet().forEach(entry -> { + RoleReference role = entry.getKey().transformToReference(); + entry.getValue().forEach(perm -> response.add(role, perm.getRestPerm())); + }); + response.setOthers(object.hasPublishPermissions()); + + return response; + }, model -> ac.send(model, OK)); + } + + /** + * Handle request to grant permissions on sets of roles + * @param ac action context + * @param uuid entity uuid + */ + public void handleGrantPermissions(InternalActionContext ac, String uuid) { + validateParameter(uuid, "uuid"); + + ObjectPermissionGrantRequest update = ac.fromJson(ObjectPermissionGrantRequest.class); + utils.syncTx(ac, tx -> { + RoleDao roleDao = tx.roleDao(); + UserDao userDao = tx.userDao(); + HibUser requestUser = ac.getUser(); + T object = crudActions().loadByUuid(context(tx, ac), uuid, READ_PERM, true); + Set allRoles = roleDao.findAll(ac, new PagingParametersImpl().setPerPage(Long.MAX_VALUE)).stream().collect(Collectors.toSet()); + Map allRolesByUuid = allRoles.stream().collect(Collectors.toMap(HibRole::getUuid, Function.identity())); + Map allRolesByName = allRoles.stream().collect(Collectors.toMap(HibRole::getName, Function.identity())); + + InternalPermission[] possiblePermissions = object.hasPublishPermissions() + ? InternalPermission.values() + : InternalPermission.basicPermissions(); + + for (InternalPermission perm : possiblePermissions) { + List roleRefsToSet = update.get(perm.getRestPerm()); + if (roleRefsToSet != null) { + Set rolesToSet = new HashSet<>(); + for (RoleReference roleRef : roleRefsToSet) { + // find the role for the role reference + HibRole role = null; + if (!StringUtils.isEmpty(roleRef.getUuid())) { + role = allRolesByUuid.get(roleRef.getUuid()); + + if (role == null) { + throw error(NOT_FOUND, "object_not_found_for_uuid", roleRef.getUuid()); + } + } else if (!StringUtils.isEmpty(roleRef.getName())) { + role = allRolesByName.get(roleRef.getName()); + + if (role == null) { + throw error(NOT_FOUND, "object_not_found_for_name", roleRef.getName()); + } + } else { + throw error(BAD_REQUEST, "role_reference_uuid_or_name_missing"); + } + + // check update permission + if (!userDao.hasPermission(requestUser, role, UPDATE_PERM)) { + throw error(FORBIDDEN, "error_missing_perm", role.getUuid(), UPDATE_PERM.getRestPerm().getName()); + } + + rolesToSet.add(role); + } + + roleDao.grantPermissions(rolesToSet, object, false, perm); + + // handle "exclusive" flag by revoking perm from all "other" roles + if (update.isExclusive()) { + // start with all roles, the user can see + Set rolesToRevoke = new HashSet<>(allRoles); + // remove all roles, which get the permission granted + rolesToRevoke.removeAll(rolesToSet); + + // remove all roles, which should be ignored + if (update.getIgnore() != null) { + rolesToRevoke.removeIf(role -> { + return update.getIgnore().stream().filter(ign -> { + return StringUtils.equals(ign.getUuid(), role.getUuid()) || StringUtils.equals(ign.getName(), role.getName()); + }).findAny().isPresent(); + }); + } + + // remove all roles without UPDATE_PERM + rolesToRevoke.removeIf(role -> !userDao.hasPermission(requestUser, role, UPDATE_PERM)); + + if (!rolesToRevoke.isEmpty()) { + roleDao.revokePermissions(rolesToRevoke, object, perm); + } + } + } + } + + Map> permissions = roleDao.getPermissions(allRoles, object); + permissions.values().removeIf(Set::isEmpty); + + ObjectPermissionResponse response = new ObjectPermissionResponse(); + permissions.entrySet().forEach(entry -> { + RoleReference role = entry.getKey().transformToReference(); + entry.getValue().forEach(perm -> response.add(role, perm.getRestPerm())); + }); + response.setOthers(object.hasPublishPermissions()); + + return response; + }, model -> ac.send(model, OK)); + } + + /** + * Handle request to revoke permissions on sets of roles + * @param ac action context + * @param uuid entity uuid + */ + public void handleRevokePermissions(InternalActionContext ac, String uuid) { + validateParameter(uuid, "uuid"); + + ObjectPermissionRevokeRequest update = ac.fromJson(ObjectPermissionRevokeRequest.class); + utils.syncTx(ac, tx -> { + RoleDao roleDao = tx.roleDao(); + UserDao userDao = tx.userDao(); + HibUser requestUser = ac.getUser(); + T object = crudActions().loadByUuid(context(tx, ac), uuid, READ_PERM, true); + Set allRoles = roleDao.findAll(ac, new PagingParametersImpl().setPerPage(Long.MAX_VALUE)).stream().collect(Collectors.toSet()); + Map allRolesByUuid = allRoles.stream().collect(Collectors.toMap(HibRole::getUuid, Function.identity())); + Map allRolesByName = allRoles.stream().collect(Collectors.toMap(HibRole::getName, Function.identity())); + + InternalPermission[] possiblePermissions = object.hasPublishPermissions() + ? InternalPermission.values() + : InternalPermission.basicPermissions(); + + for (InternalPermission perm : possiblePermissions) { + List roleRefsToRevoke = update.get(perm.getRestPerm()); + if (roleRefsToRevoke != null) { + Set rolesToRevoke = new HashSet<>(); + for (RoleReference roleRef : roleRefsToRevoke) { + // find the role for the role reference + HibRole role = null; + if (!StringUtils.isEmpty(roleRef.getUuid())) { + role = allRolesByUuid.get(roleRef.getUuid()); + + if (role == null) { + throw error(NOT_FOUND, "object_not_found_for_uuid", roleRef.getUuid()); + } + } else if (!StringUtils.isEmpty(roleRef.getName())) { + role = allRolesByName.get(roleRef.getName()); + + if (role == null) { + throw error(NOT_FOUND, "object_not_found_for_name", roleRef.getName()); + } + } else { + throw error(BAD_REQUEST, "role_reference_uuid_or_name_missing"); + } + + // check update permission + if (!userDao.hasPermission(requestUser, role, UPDATE_PERM)) { + throw error(FORBIDDEN, "error_missing_perm", role.getUuid(), UPDATE_PERM.getRestPerm().getName()); + } + + rolesToRevoke.add(role); + } + + roleDao.revokePermissions(rolesToRevoke, object, perm); + } + } + + Map> permissions = roleDao.getPermissions(allRoles, object); + permissions.values().removeIf(Set::isEmpty); + + ObjectPermissionResponse response = new ObjectPermissionResponse(); + permissions.entrySet().forEach(entry -> { + RoleReference role = entry.getKey().transformToReference(); + entry.getValue().forEach(perm -> response.add(role, perm.getRestPerm())); + }); + response.setOthers(object.hasPublishPermissions()); + + return response; + }, model -> ac.send(model, OK)); + } } diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaEndpoint.java index 088ba30f92..3b8f297853 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaEndpoint.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaEndpoint.java @@ -21,15 +21,15 @@ import com.gentics.mesh.auth.MeshAuthChainImpl; import com.gentics.mesh.context.InternalActionContext; +import com.gentics.mesh.core.endpoint.RolePermissionHandlingEndpoint; import com.gentics.mesh.parameter.impl.PagingParametersImpl; import com.gentics.mesh.parameter.impl.VersioningParametersImpl; import com.gentics.mesh.rest.InternalEndpointRoute; -import com.gentics.mesh.router.route.AbstractInternalEndpoint; /** * Endpoint for /api/v1/microschemas */ -public class MicroschemaEndpoint extends AbstractInternalEndpoint { +public class MicroschemaEndpoint extends RolePermissionHandlingEndpoint { private MicroschemaCrudHandler crudHandler; @@ -59,6 +59,7 @@ public void registerEndPoints() { addReadHandlers(); addUpdateHandler(); addDeleteHandler(); + addRolePermissionHandler("microschemaUuid", MICROSCHEMA_UUID, "microschema", crudHandler, false); } private void addDiffHandler() { @@ -189,5 +190,4 @@ private void addCreateHandler() { crudHandler.handleCreate(wrap(rc)); }); } - } diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/node/NodeEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/node/NodeEndpoint.java index 3543361d4a..a11a1bcd99 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/node/NodeEndpoint.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/node/NodeEndpoint.java @@ -1,8 +1,39 @@ package com.gentics.mesh.core.endpoint.node; +import static com.gentics.mesh.core.rest.MeshEvent.NODE_CONTENT_CREATED; +import static com.gentics.mesh.core.rest.MeshEvent.NODE_CONTENT_DELETED; +import static com.gentics.mesh.core.rest.MeshEvent.NODE_CREATED; +import static com.gentics.mesh.core.rest.MeshEvent.NODE_DELETED; +import static com.gentics.mesh.core.rest.MeshEvent.NODE_MOVED; +import static com.gentics.mesh.core.rest.MeshEvent.NODE_PUBLISHED; +import static com.gentics.mesh.core.rest.MeshEvent.NODE_TAGGED; +import static com.gentics.mesh.core.rest.MeshEvent.NODE_UNPUBLISHED; +import static com.gentics.mesh.core.rest.MeshEvent.NODE_UNTAGGED; +import static com.gentics.mesh.core.rest.MeshEvent.NODE_UPDATED; +import static com.gentics.mesh.core.rest.MeshEvent.S3BINARY_CREATED; +import static com.gentics.mesh.core.rest.MeshEvent.S3BINARY_METADATA_EXTRACTED; +import static com.gentics.mesh.example.ExampleUuids.NODE_DELOREAN_UUID; +import static com.gentics.mesh.example.ExampleUuids.TAG_RED_UUID; +import static com.gentics.mesh.example.ExampleUuids.UUID_1; +import static com.gentics.mesh.http.HttpConstants.APPLICATION_JSON; +import static io.netty.handler.codec.http.HttpResponseStatus.CONFLICT; +import static io.netty.handler.codec.http.HttpResponseStatus.CREATED; +import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; +import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT; +import static io.netty.handler.codec.http.HttpResponseStatus.OK; +import static io.vertx.core.http.HttpMethod.DELETE; +import static io.vertx.core.http.HttpMethod.GET; +import static io.vertx.core.http.HttpMethod.POST; + +import javax.inject.Inject; + +import org.apache.commons.lang3.StringUtils; +import org.raml.model.Resource; + import com.gentics.mesh.auth.MeshAuthChainImpl; import com.gentics.mesh.cli.BootstrapInitializer; import com.gentics.mesh.context.InternalActionContext; +import com.gentics.mesh.core.endpoint.RolePermissionHandlingProjectEndpoint; import com.gentics.mesh.core.rest.navigation.NavigationResponse; import com.gentics.mesh.parameter.impl.DeleteParametersImpl; import com.gentics.mesh.parameter.impl.GenericParametersImpl; @@ -14,31 +45,13 @@ import com.gentics.mesh.parameter.impl.RolePermissionParametersImpl; import com.gentics.mesh.parameter.impl.VersioningParametersImpl; import com.gentics.mesh.rest.InternalEndpointRoute; -import com.gentics.mesh.router.route.AbstractProjectEndpoint; -import io.vertx.core.MultiMap; -import org.apache.commons.lang3.StringUtils; -import org.raml.model.Resource; - -import javax.inject.Inject; -import static com.gentics.mesh.core.rest.MeshEvent.*; -import static com.gentics.mesh.example.ExampleUuids.NODE_DELOREAN_UUID; -import static com.gentics.mesh.example.ExampleUuids.TAG_RED_UUID; -import static com.gentics.mesh.example.ExampleUuids.UUID_1; -import static com.gentics.mesh.http.HttpConstants.APPLICATION_JSON; -import static io.netty.handler.codec.http.HttpResponseStatus.CONFLICT; -import static io.netty.handler.codec.http.HttpResponseStatus.CREATED; -import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; -import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT; -import static io.netty.handler.codec.http.HttpResponseStatus.OK; -import static io.vertx.core.http.HttpMethod.DELETE; -import static io.vertx.core.http.HttpMethod.GET; -import static io.vertx.core.http.HttpMethod.POST; +import io.vertx.core.MultiMap; /** * The content verticle adds rest endpoints for manipulating nodes. */ -public class NodeEndpoint extends AbstractProjectEndpoint { +public class NodeEndpoint extends RolePermissionHandlingProjectEndpoint { private Resource resource = new Resource(); @@ -98,6 +111,7 @@ public void registerEndPoints() { addNavigationHandlers(); addPublishHandlers(); addVersioningHandlers(); + addRolePermissionHandler("nodeUuid", NODE_DELOREAN_UUID, "node", crudHandler, true); } public Resource getResource() { diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/project/ProjectEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/project/ProjectEndpoint.java index 32e88b9fe7..b0cb54165e 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/project/ProjectEndpoint.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/project/ProjectEndpoint.java @@ -20,16 +20,16 @@ import com.gentics.mesh.auth.MeshAuthChainImpl; import com.gentics.mesh.context.InternalActionContext; +import com.gentics.mesh.core.endpoint.RolePermissionHandlingEndpoint; import com.gentics.mesh.parameter.impl.PagingParametersImpl; import com.gentics.mesh.parameter.impl.ProjectPurgeParametersImpl; import com.gentics.mesh.parameter.impl.RolePermissionParametersImpl; import com.gentics.mesh.rest.InternalEndpointRoute; -import com.gentics.mesh.router.route.AbstractInternalEndpoint; /** * Endpoint for /api/v1/projects */ -public class ProjectEndpoint extends AbstractInternalEndpoint { +public class ProjectEndpoint extends RolePermissionHandlingEndpoint { private ProjectCrudHandler crudHandler; @@ -59,6 +59,8 @@ public void registerEndPoints() { // Version purge addVersionPurgeHandler(); + + addRolePermissionHandler("projectUuid", PROJECT_DEMO_UUID, "project", crudHandler, false); } private void addUpdateHandler() { diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/role/RoleEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/role/RoleEndpoint.java index 9c41e0fa0a..625fa6c415 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/role/RoleEndpoint.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/role/RoleEndpoint.java @@ -19,15 +19,15 @@ import com.gentics.mesh.auth.MeshAuthChainImpl; import com.gentics.mesh.context.InternalActionContext; +import com.gentics.mesh.core.endpoint.RolePermissionHandlingEndpoint; import com.gentics.mesh.parameter.impl.GenericParametersImpl; import com.gentics.mesh.parameter.impl.PagingParametersImpl; import com.gentics.mesh.rest.InternalEndpointRoute; -import com.gentics.mesh.router.route.AbstractInternalEndpoint; /** * Endpoint for /api/v1/roles */ -public class RoleEndpoint extends AbstractInternalEndpoint { +public class RoleEndpoint extends RolePermissionHandlingEndpoint { private RoleCrudHandlerImpl crudHandler; @@ -56,6 +56,7 @@ public void registerEndPoints() { addDeleteHandler(); addPermissionHandler(); + addRolePermissionHandler("roleUuid", ROLE_CLIENT_UUID, "role", crudHandler, false); } private void addPermissionHandler() { diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaEndpoint.java index 33d3f60ad2..510f892d87 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaEndpoint.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaEndpoint.java @@ -21,17 +21,17 @@ import com.gentics.mesh.auth.MeshAuthChainImpl; import com.gentics.mesh.context.InternalActionContext; +import com.gentics.mesh.core.endpoint.RolePermissionHandlingEndpoint; import com.gentics.mesh.parameter.impl.GenericParametersImpl; import com.gentics.mesh.parameter.impl.PagingParametersImpl; import com.gentics.mesh.parameter.impl.SchemaUpdateParametersImpl; import com.gentics.mesh.parameter.impl.VersioningParametersImpl; import com.gentics.mesh.rest.InternalEndpointRoute; -import com.gentics.mesh.router.route.AbstractInternalEndpoint; /** * Verticle for /api/v2/schemas endpoint */ -public class SchemaEndpoint extends AbstractInternalEndpoint { +public class SchemaEndpoint extends RolePermissionHandlingEndpoint { private SchemaCrudHandler crudHandler; @@ -63,6 +63,8 @@ public void registerEndPoints() { addCreateHandler(); addUpdateHandler(); addDeleteHandler(); + + addRolePermissionHandler("schemaUuid", SCHEMA_VEHICLE_UUID, "schema", crudHandler, false); } private void addChangesHandler() { diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/tag/TagCrudHandler.java b/core/src/main/java/com/gentics/mesh/core/endpoint/tag/TagCrudHandler.java index b6881cd756..875d9510ef 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/tag/TagCrudHandler.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/tag/TagCrudHandler.java @@ -2,31 +2,53 @@ import static com.gentics.mesh.core.action.DAOActionContext.context; import static com.gentics.mesh.core.data.perm.InternalPermission.READ_PERM; +import static com.gentics.mesh.core.data.perm.InternalPermission.UPDATE_PERM; +import static com.gentics.mesh.core.rest.error.Errors.error; +import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; import static io.netty.handler.codec.http.HttpResponseStatus.CREATED; +import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; +import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; import static io.netty.handler.codec.http.HttpResponseStatus.OK; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.function.Function; +import java.util.stream.Collectors; import javax.inject.Inject; +import org.apache.commons.lang3.StringUtils; + import com.gentics.mesh.context.InternalActionContext; import com.gentics.mesh.core.action.TagDAOActions; import com.gentics.mesh.core.action.TagFamilyDAOActions; +import com.gentics.mesh.core.data.dao.RoleDao; import com.gentics.mesh.core.data.dao.TagDao; +import com.gentics.mesh.core.data.dao.UserDao; import com.gentics.mesh.core.data.node.HibNode; import com.gentics.mesh.core.data.page.Page; import com.gentics.mesh.core.data.page.PageTransformer; +import com.gentics.mesh.core.data.perm.InternalPermission; +import com.gentics.mesh.core.data.role.HibRole; import com.gentics.mesh.core.data.tag.HibTag; import com.gentics.mesh.core.data.tagfamily.HibTagFamily; +import com.gentics.mesh.core.data.user.HibUser; import com.gentics.mesh.core.db.Tx; import com.gentics.mesh.core.endpoint.handler.AbstractHandler; import com.gentics.mesh.core.rest.common.ContainerType; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; +import com.gentics.mesh.core.rest.role.RoleReference; import com.gentics.mesh.core.rest.tag.TagResponse; import com.gentics.mesh.core.verticle.handler.HandlerUtilities; import com.gentics.mesh.core.verticle.handler.WriteLock; import com.gentics.mesh.etc.config.MeshOptions; import com.gentics.mesh.parameter.NodeParameters; import com.gentics.mesh.parameter.PagingParameters; +import com.gentics.mesh.parameter.impl.PagingParametersImpl; import com.gentics.mesh.util.ResultInfo; /** @@ -188,4 +210,204 @@ public void handleDelete(InternalActionContext ac, String tagFamilyUuid, String } + /** + * Handle request to read the permissions for all roles + * @param ac action context + * @param tagFamilyUuid Uuid of the tag family + * @param tagUuid Uuid of the tag + */ + public void handleReadPermissions(InternalActionContext ac, String tagFamilyUuid, String tagUuid) { + validateParameter(tagFamilyUuid, "tagFamilyUuid"); + validateParameter(tagUuid, "tagUuid"); + + utils.syncTx(ac, tx -> { + RoleDao roleDao = tx.roleDao(); + HibTagFamily tagFamily = tagFamilyActions.loadByUuid(context(tx, ac), tagFamilyUuid, READ_PERM, true); + HibTag tag = tagActions.loadByUuid(context(tx, ac, tagFamily), tagUuid, READ_PERM, true); + + Set roles = roleDao.findAll(ac, new PagingParametersImpl().setPerPage(Long.MAX_VALUE)).stream().collect(Collectors.toSet()); + + Map> permissions = roleDao.getPermissions(roles, tag); + permissions.values().removeIf(Set::isEmpty); + + ObjectPermissionResponse response = new ObjectPermissionResponse(); + permissions.entrySet().forEach(entry -> { + RoleReference role = entry.getKey().transformToReference(); + entry.getValue().forEach(perm -> response.add(role, perm.getRestPerm())); + }); + response.setOthers(tag.hasPublishPermissions()); + + return response; + }, model -> ac.send(model, OK)); + } + + /** + * Handle request to grant permissions on sets of roles + * @param ac action context + * @param tagFamilyUuid Uuid of the tag family + * @param tagUuid Uuid of the tag + */ + public void handleGrantPermissions(InternalActionContext ac, String tagFamilyUuid, String tagUuid) { + validateParameter(tagFamilyUuid, "tagFamilyUuid"); + validateParameter(tagUuid, "tagUuid"); + + ObjectPermissionGrantRequest update = ac.fromJson(ObjectPermissionGrantRequest.class); + utils.syncTx(ac, tx -> { + RoleDao roleDao = tx.roleDao(); + UserDao userDao = tx.userDao(); + HibUser requestUser = ac.getUser(); + HibTagFamily tagFamily = tagFamilyActions.loadByUuid(context(tx, ac), tagFamilyUuid, READ_PERM, true); + HibTag tag = tagActions.loadByUuid(context(tx, ac, tagFamily), tagUuid, READ_PERM, true); + + Set allRoles = roleDao.findAll(ac, new PagingParametersImpl().setPerPage(Long.MAX_VALUE)).stream().collect(Collectors.toSet()); + Map allRolesByUuid = allRoles.stream().collect(Collectors.toMap(HibRole::getUuid, Function.identity())); + Map allRolesByName = allRoles.stream().collect(Collectors.toMap(HibRole::getName, Function.identity())); + + InternalPermission[] possiblePermissions = InternalPermission.basicPermissions(); + + for (InternalPermission perm : possiblePermissions) { + List roleRefsToSet = update.get(perm.getRestPerm()); + if (roleRefsToSet != null) { + Set rolesToSet = new HashSet<>(); + for (RoleReference roleRef : roleRefsToSet) { + // find the role for the role reference + HibRole role = null; + if (!StringUtils.isEmpty(roleRef.getUuid())) { + role = allRolesByUuid.get(roleRef.getUuid()); + + if (role == null) { + throw error(NOT_FOUND, "object_not_found_for_uuid", roleRef.getUuid()); + } + } else if (!StringUtils.isEmpty(roleRef.getName())) { + role = allRolesByName.get(roleRef.getName()); + + if (role == null) { + throw error(NOT_FOUND, "object_not_found_for_name", roleRef.getName()); + } + } else { + throw error(BAD_REQUEST, "role_reference_uuid_or_name_missing"); + } + + // check update permission + if (!userDao.hasPermission(requestUser, role, UPDATE_PERM)) { + throw error(FORBIDDEN, "error_missing_perm", role.getUuid(), UPDATE_PERM.getRestPerm().getName()); + } + + rolesToSet.add(role); + } + + roleDao.grantPermissions(rolesToSet, tag, false, perm); + + // handle "exclusive" flag by revoking perm from all "other" roles + if (update.isExclusive()) { + // start with all roles, the user can see + Set rolesToRevoke = new HashSet<>(allRoles); + // remove all roles, which get the permission granted + rolesToRevoke.removeAll(rolesToSet); + + // remove all roles, which should be ignored + if (update.getIgnore() != null) { + rolesToRevoke.removeIf(role -> { + return update.getIgnore().stream().filter(ign -> { + return StringUtils.equals(ign.getUuid(), role.getUuid()) || StringUtils.equals(ign.getName(), role.getName()); + }).findAny().isPresent(); + }); + } + + // remove all roles without UPDATE_PERM + rolesToRevoke.removeIf(role -> !userDao.hasPermission(requestUser, role, UPDATE_PERM)); + + if (!rolesToRevoke.isEmpty()) { + roleDao.revokePermissions(rolesToRevoke, tag, perm); + } + } + } + } + + Map> permissions = roleDao.getPermissions(allRoles, tag); + permissions.values().removeIf(Set::isEmpty); + + ObjectPermissionResponse response = new ObjectPermissionResponse(); + permissions.entrySet().forEach(entry -> { + RoleReference role = entry.getKey().transformToReference(); + entry.getValue().forEach(perm -> response.add(role, perm.getRestPerm())); + }); + response.setOthers(false); + + return response; + }, model -> ac.send(model, OK)); + } + + /** + * Handle request to revoke permissions on sets of roles + * @param ac action context + * @param tagFamilyUuid Uuid of the tag family + * @param tagUuid Uuid of the tag + */ + public void handleRevokePermissions(InternalActionContext ac, String tagFamilyUuid, String tagUuid) { + validateParameter(tagFamilyUuid, "tagFamilyUuid"); + validateParameter(tagUuid, "tagUuid"); + + ObjectPermissionRevokeRequest update = ac.fromJson(ObjectPermissionRevokeRequest.class); + utils.syncTx(ac, tx -> { + RoleDao roleDao = tx.roleDao(); + UserDao userDao = tx.userDao(); + HibUser requestUser = ac.getUser(); + HibTagFamily tagFamily = tagFamilyActions.loadByUuid(context(tx, ac), tagFamilyUuid, READ_PERM, true); + HibTag tag = tagActions.loadByUuid(context(tx, ac, tagFamily), tagUuid, READ_PERM, true); + + Set allRoles = roleDao.findAll(ac, new PagingParametersImpl().setPerPage(Long.MAX_VALUE)).stream().collect(Collectors.toSet()); + Map allRolesByUuid = allRoles.stream().collect(Collectors.toMap(HibRole::getUuid, Function.identity())); + Map allRolesByName = allRoles.stream().collect(Collectors.toMap(HibRole::getName, Function.identity())); + + InternalPermission[] possiblePermissions = InternalPermission.basicPermissions(); + + for (InternalPermission perm : possiblePermissions) { + List roleRefsToRevoke = update.get(perm.getRestPerm()); + if (roleRefsToRevoke != null) { + Set rolesToRevoke = new HashSet<>(); + for (RoleReference roleRef : roleRefsToRevoke) { + // find the role for the role reference + HibRole role = null; + if (!StringUtils.isEmpty(roleRef.getUuid())) { + role = allRolesByUuid.get(roleRef.getUuid()); + + if (role == null) { + throw error(NOT_FOUND, "object_not_found_for_uuid", roleRef.getUuid()); + } + } else if (!StringUtils.isEmpty(roleRef.getName())) { + role = allRolesByName.get(roleRef.getName()); + + if (role == null) { + throw error(NOT_FOUND, "object_not_found_for_name", roleRef.getName()); + } + } else { + throw error(BAD_REQUEST, "role_reference_uuid_or_name_missing"); + } + + // check update permission + if (!userDao.hasPermission(requestUser, role, UPDATE_PERM)) { + throw error(FORBIDDEN, "error_missing_perm", role.getUuid(), UPDATE_PERM.getRestPerm().getName()); + } + + rolesToRevoke.add(role); + } + + roleDao.revokePermissions(rolesToRevoke, tag, perm); + } + } + + Map> permissions = roleDao.getPermissions(allRoles, tag); + permissions.values().removeIf(Set::isEmpty); + + ObjectPermissionResponse response = new ObjectPermissionResponse(); + permissions.entrySet().forEach(entry -> { + RoleReference role = entry.getKey().transformToReference(); + entry.getValue().forEach(perm -> response.add(role, perm.getRestPerm())); + }); + response.setOthers(false); + + return response; + }, model -> ac.send(model, OK)); + } } diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/tagfamily/TagFamilyEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/tagfamily/TagFamilyEndpoint.java index 465a4e9bf7..632bf81211 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/tagfamily/TagFamilyEndpoint.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/tagfamily/TagFamilyEndpoint.java @@ -1,6 +1,7 @@ package com.gentics.mesh.core.endpoint.tagfamily; import static com.gentics.mesh.core.rest.MeshEvent.NODE_UNTAGGED; +import static com.gentics.mesh.core.rest.MeshEvent.ROLE_PERMISSIONS_CHANGED; import static com.gentics.mesh.core.rest.MeshEvent.TAG_CREATED; import static com.gentics.mesh.core.rest.MeshEvent.TAG_DELETED; import static com.gentics.mesh.core.rest.MeshEvent.TAG_FAMILY_CREATED; @@ -23,11 +24,11 @@ import com.gentics.mesh.cli.BootstrapInitializer; import com.gentics.mesh.context.InternalActionContext; import com.gentics.mesh.core.endpoint.PathParameters; +import com.gentics.mesh.core.endpoint.RolePermissionHandlingProjectEndpoint; import com.gentics.mesh.core.endpoint.tag.TagCrudHandler; import com.gentics.mesh.parameter.impl.GenericParametersImpl; import com.gentics.mesh.parameter.impl.PagingParametersImpl; import com.gentics.mesh.rest.InternalEndpointRoute; -import com.gentics.mesh.router.route.AbstractProjectEndpoint; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; @@ -35,7 +36,7 @@ /** * Endpoint for /api/v1/:project/tagFamilies */ -public class TagFamilyEndpoint extends AbstractProjectEndpoint { +public class TagFamilyEndpoint extends RolePermissionHandlingProjectEndpoint { private static final Logger log = LoggerFactory.getLogger(TagFamilyEndpoint.class); @@ -72,6 +73,7 @@ public void registerEndPoints() { addTagFamilyCreateHandler(); addTagFamilyUpdateHandler(); addTagFamilyDeleteHandler(); + addRolePermissionHandler("tagFamilyUuid", TAGFAMILY_COLORS_UUID, "tag family", tagFamilyCrudHandler, false); // Tags API addTagCreateHandler(); @@ -79,6 +81,7 @@ public void registerEndPoints() { addTagUpdateHandler(); addTagDeleteHandler(); addTaggedNodesHandler(); + addTagRolePermissionHandler(); if (log.isDebugEnabled()) { log.debug("Registered tagfamily verticle endpoints"); @@ -174,6 +177,59 @@ private void addTagDeleteHandler() { }); } + private void addTagRolePermissionHandler() { + InternalEndpointRoute readPermissionsEndpoint = createRoute(); + readPermissionsEndpoint.path("/:tagFamilyUuid/tags/:tagUuid/rolePermissions"); + readPermissionsEndpoint.addUriParameter("tagFamilyUuid", "Uuid of the tag family.", TAGFAMILY_COLORS_UUID); + readPermissionsEndpoint.addUriParameter("tagUuid", "Uuid of the tag.", TAG_BLUE_UUID); + readPermissionsEndpoint.method(GET); + readPermissionsEndpoint.description("Get the permissions on the tag for all roles."); + readPermissionsEndpoint.produces(APPLICATION_JSON); + readPermissionsEndpoint.exampleResponse(OK, roleExamples.getObjectPermissionResponse(false), "Loaded permissions."); + readPermissionsEndpoint.blockingHandler(rc -> { + InternalActionContext ac = wrap(rc); + String tagFamilyUuid = PathParameters.getTagFamilyUuid(rc); + String uuid = PathParameters.getTagUuid(rc); + tagCrudHandler.handleReadPermissions(ac, tagFamilyUuid, uuid); + }, false); + + InternalEndpointRoute grantPermissionsEndpoint = createRoute(); + grantPermissionsEndpoint.path("/:tagFamilyUuid/tags/:tagUuid/rolePermissions"); + readPermissionsEndpoint.addUriParameter("tagFamilyUuid", "Uuid of the tag family.", TAGFAMILY_COLORS_UUID); + readPermissionsEndpoint.addUriParameter("tagUuid", "Uuid of the tag.", TAG_BLUE_UUID); + grantPermissionsEndpoint.method(POST); + grantPermissionsEndpoint.description("Grant permissions on the tag to multiple roles."); + grantPermissionsEndpoint.consumes(APPLICATION_JSON); + grantPermissionsEndpoint.produces(APPLICATION_JSON); + grantPermissionsEndpoint.exampleRequest(roleExamples.getObjectPermissionGrantRequest(false)); + grantPermissionsEndpoint.exampleResponse(OK, roleExamples.getObjectPermissionResponse(false), "Updated permissions."); + grantPermissionsEndpoint.events(ROLE_PERMISSIONS_CHANGED); + grantPermissionsEndpoint.blockingHandler(rc -> { + InternalActionContext ac = wrap(rc); + String tagFamilyUuid = PathParameters.getTagFamilyUuid(rc); + String uuid = PathParameters.getTagUuid(rc); + tagCrudHandler.handleGrantPermissions(ac, tagFamilyUuid, uuid); + }); + + InternalEndpointRoute revokePermissionsEndpoint = createRoute(); + revokePermissionsEndpoint.path("/:tagFamilyUuid/tags/:tagUuid/rolePermissions"); + readPermissionsEndpoint.addUriParameter("tagFamilyUuid", "Uuid of the tag family.", TAGFAMILY_COLORS_UUID); + readPermissionsEndpoint.addUriParameter("tagUuid", "Uuid of the tag.", TAG_BLUE_UUID); + revokePermissionsEndpoint.method(DELETE); + revokePermissionsEndpoint.description("Revoke permissions on the tag from multiple roles."); + revokePermissionsEndpoint.consumes(APPLICATION_JSON); + revokePermissionsEndpoint.produces(APPLICATION_JSON); + revokePermissionsEndpoint.exampleRequest(roleExamples.getObjectPermissionRevokeRequest(false)); + revokePermissionsEndpoint.exampleResponse(OK, roleExamples.getObjectPermissionResponse(false), "Updated permissions."); + revokePermissionsEndpoint.events(ROLE_PERMISSIONS_CHANGED); + revokePermissionsEndpoint.blockingHandler(rc -> { + InternalActionContext ac = wrap(rc); + String tagFamilyUuid = PathParameters.getTagFamilyUuid(rc); + String uuid = PathParameters.getTagUuid(rc); + tagCrudHandler.handleRevokePermissions(ac, tagFamilyUuid, uuid); + }); + } + private void addTaggedNodesHandler() { InternalEndpointRoute endpoint = createRoute(); endpoint.path("/:tagFamilyUuid/tags/:tagUuid/nodes"); diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/user/UserEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/user/UserEndpoint.java index 5f5dd62421..086a7b69aa 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/user/UserEndpoint.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/user/UserEndpoint.java @@ -16,6 +16,7 @@ import com.gentics.mesh.auth.MeshAuthChainImpl; import com.gentics.mesh.context.InternalActionContext; +import com.gentics.mesh.core.endpoint.RolePermissionHandlingEndpoint; import com.gentics.mesh.parameter.impl.GenericParametersImpl; import com.gentics.mesh.parameter.impl.NodeParametersImpl; import com.gentics.mesh.parameter.impl.PagingParametersImpl; @@ -23,14 +24,13 @@ import com.gentics.mesh.parameter.impl.UserParametersImpl; import com.gentics.mesh.parameter.impl.VersioningParametersImpl; import com.gentics.mesh.rest.InternalEndpointRoute; -import com.gentics.mesh.router.route.AbstractInternalEndpoint; import io.vertx.core.http.HttpHeaders; /** * Endpoint for /api/v1/users */ -public class UserEndpoint extends AbstractInternalEndpoint { +public class UserEndpoint extends RolePermissionHandlingEndpoint { private UserCrudHandler crudHandler; @@ -63,6 +63,7 @@ public void registerEndPoints() { addResetTokenHandler(); addAPITokenHandler(); addReadPermissionHandler(); + addRolePermissionHandler("userUuid", USER_EDITOR_UUID, "user", crudHandler, false); } private void addAPITokenHandler() { diff --git a/core/src/main/java/com/gentics/mesh/rest/MeshLocalClientImpl.java b/core/src/main/java/com/gentics/mesh/rest/MeshLocalClientImpl.java index 412fcc78f7..bc623d54d3 100644 --- a/core/src/main/java/com/gentics/mesh/rest/MeshLocalClientImpl.java +++ b/core/src/main/java/com/gentics/mesh/rest/MeshLocalClientImpl.java @@ -51,6 +51,9 @@ import com.gentics.mesh.core.rest.branch.info.BranchInfoMicroschemaList; import com.gentics.mesh.core.rest.branch.info.BranchInfoSchemaList; import com.gentics.mesh.core.rest.common.GenericMessageResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.common.RestModel; import com.gentics.mesh.core.rest.graphql.GraphQLRequest; import com.gentics.mesh.core.rest.graphql.GraphQLResponse; @@ -1863,4 +1866,278 @@ public MeshRequest writable() { public MeshRequest clearCache() { return null; } + + @Override + public MeshRequest getBranchRolePermissions(String projectName, String uuid) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setProject(projectName); + branchCrudHandler.handleReadPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest grantBranchRolePermissions(String projectName, String uuid, + ObjectPermissionGrantRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setProject(projectName); + ac.setPayloadObject(request); + branchCrudHandler.handleGrantPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest revokeBranchRolePermissions(String projectName, String uuid, + ObjectPermissionRevokeRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setProject(projectName); + ac.setPayloadObject(request); + branchCrudHandler.handleRevokePermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest getGroupRolePermissions(String uuid) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + groupCrudHandler.handleReadPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest grantGroupRolePermissions(String uuid, + ObjectPermissionGrantRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setPayloadObject(request); + groupCrudHandler.handleGrantPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest revokeGroupRolePermissions(String uuid, + ObjectPermissionRevokeRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setPayloadObject(request); + groupCrudHandler.handleRevokePermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest getMicroschemaRolePermissions(String uuid) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + microschemaCrudHandler.handleReadPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest grantMicroschemaRolePermissions(String uuid, + ObjectPermissionGrantRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setPayloadObject(request); + microschemaCrudHandler.handleGrantPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest revokeMicroschemaRolePermissions(String uuid, + ObjectPermissionRevokeRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setPayloadObject(request); + microschemaCrudHandler.handleRevokePermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest getNodeRolePermissions(String projectName, String uuid) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setProject(projectName); + nodeCrudHandler.handleReadPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest grantNodeRolePermissions(String projectName, String uuid, + ObjectPermissionGrantRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setProject(projectName); + ac.setPayloadObject(request); + nodeCrudHandler.handleGrantPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest revokeNodeRolePermissions(String projectName, String uuid, + ObjectPermissionRevokeRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setProject(projectName); + ac.setPayloadObject(request); + nodeCrudHandler.handleRevokePermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest getProjectRolePermissions(String uuid) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + projectCrudHandler.handleReadPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest grantProjectRolePermissions(String uuid, + ObjectPermissionGrantRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setPayloadObject(request); + projectCrudHandler.handleGrantPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest revokeProjectRolePermissions(String uuid, + ObjectPermissionRevokeRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setPayloadObject(request); + projectCrudHandler.handleRevokePermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest getRoleRolePermissions(String uuid) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + roleCrudHandler.handleReadPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest grantRoleRolePermissions(String uuid, + ObjectPermissionGrantRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setPayloadObject(request); + roleCrudHandler.handleGrantPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest revokeRoleRolePermissions(String uuid, + ObjectPermissionRevokeRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setPayloadObject(request); + roleCrudHandler.handleRevokePermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest getSchemaRolePermissions(String uuid) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + schemaCrudHandler.handleReadPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest grantSchemaRolePermissions(String uuid, + ObjectPermissionGrantRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setPayloadObject(request); + schemaCrudHandler.handleGrantPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest revokeSchemaRolePermissions(String uuid, + ObjectPermissionRevokeRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setPayloadObject(request); + schemaCrudHandler.handleRevokePermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest getTagFamilyRolePermissions(String projectName, String tagFamilyUuid) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setProject(projectName); + ac.setParameter("tagFamilyUuid", tagFamilyUuid); + tagFamilyCrudHandler.handleReadPermissions(ac, tagFamilyUuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest grantTagFamilyRolePermissions(String projectName, String tagFamilyUuid, + ObjectPermissionGrantRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setProject(projectName); + ac.setParameter("tagFamilyUuid", tagFamilyUuid); + ac.setPayloadObject(request); + tagFamilyCrudHandler.handleGrantPermissions(ac, tagFamilyUuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest revokeTagFamilyRolePermissions(String projectName, String tagFamilyUuid, + ObjectPermissionRevokeRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setProject(projectName); + ac.setParameter("tagFamilyUuid", tagFamilyUuid); + ac.setPayloadObject(request); + tagFamilyCrudHandler.handleRevokePermissions(ac, tagFamilyUuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest getTagRolePermissions(String projectName, String tagFamilyUuid, + String uuid) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setProject(projectName); + ac.setParameter("tagUuid", uuid); + ac.setParameter("tagFamilyUuid", tagFamilyUuid); + tagCrudHandler.handleReadPermissions(ac, tagFamilyUuid, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest grantTagRolePermissions(String projectName, String tagFamilyUuid, + String uuid, + ObjectPermissionGrantRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setProject(projectName); + ac.setParameter("tagUuid", uuid); + ac.setParameter("tagFamilyUuid", tagFamilyUuid); + ac.setPayloadObject(request); + tagCrudHandler.handleGrantPermissions(ac, tagFamilyUuid, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest revokeTagRolePermissions(String projectName, String tagFamilyUuid, + String uuid, + ObjectPermissionRevokeRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setProject(projectName); + ac.setParameter("tagUuid", uuid); + ac.setParameter("tagFamilyUuid", tagFamilyUuid); + ac.setPayloadObject(request); + tagCrudHandler.handleRevokePermissions(ac, tagFamilyUuid, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest getUserRolePermissions(String uuid) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + userCrudHandler.handleReadPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest grantUserRolePermissions(String uuid, + ObjectPermissionGrantRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setPayloadObject(request); + userCrudHandler.handleGrantPermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest revokeUserRolePermissions(String uuid, + ObjectPermissionRevokeRequest request) { + LocalActionContextImpl ac = createContext(ObjectPermissionResponse.class); + ac.setPayloadObject(request); + userCrudHandler.handleRevokePermissions(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } } diff --git a/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/RoleDao.java b/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/RoleDao.java index 59ab5b40d9..b2c666a43f 100644 --- a/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/RoleDao.java +++ b/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/RoleDao.java @@ -1,5 +1,6 @@ package com.gentics.mesh.core.data.dao; +import java.util.Map; import java.util.Set; import com.gentics.mesh.context.InternalActionContext; @@ -68,6 +69,17 @@ default HibRole create(String name, HibUser creator) { */ boolean grantPermissions(HibRole role, HibBaseElement element, InternalPermission... permissions); + /** + * Grant the given permissions on the element to the set of roles + * + * @param roles set of roles + * @param element element to grant permission on + * @param exclusive true to revoke the given permissions on all other roles + * @param permissions permissions to grant + * @return true, iff permissions were effectively changed + */ + boolean grantPermissions(Set roles, HibBaseElement element, boolean exclusive, InternalPermission... permissions); + /** * Revoke the given permissions on the given role. * @@ -78,6 +90,16 @@ default HibRole create(String name, HibUser creator) { */ boolean revokePermissions(HibRole role, HibBaseElement element, InternalPermission... permissions); + /** + * Revoke the given permissions on the element from the given roles. + * + * @param roles set of roles + * @param element element to revoke permissions from + * @param permissions permissions to revoke + * @return true, iff permissions were effectively changed + */ + boolean revokePermissions(Set roles, HibBaseElement element, InternalPermission... permissions); + /** * Return a set of permissions which the role is granting to the given element. * @@ -87,6 +109,15 @@ default HibRole create(String name, HibUser creator) { */ Set getPermissions(HibRole role, HibBaseElement element); + /** + * Return the sets of granted permissions to the given set of roles on the given element + * + * @param roles set of roles + * @param element element + * @return map of permission sets per role + */ + Map> getPermissions(Set roles, HibBaseElement element); + /** * Add the given role to this role. * diff --git a/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingRoleDao.java b/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingRoleDao.java index f63a1c25be..9959dc881a 100644 --- a/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingRoleDao.java +++ b/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingRoleDao.java @@ -8,11 +8,15 @@ import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; import static org.apache.commons.lang3.StringUtils.isEmpty; +import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Stream; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import com.gentics.mesh.cache.PermissionCache; @@ -42,95 +46,137 @@ * */ public interface PersistingRoleDao extends RoleDao, PersistingDaoGlobal { - /** - * Grant role permission. Consumers implementing this method do not need to invalidate the cache - * @param role the role - * @param element - * @param permissions - */ - boolean grantRolePermissions(HibRole role, HibBaseElement element, InternalPermission... permissions); - - /** - * Revoke role permission. Consumers implementing this method do not need to invalidate the cache - * @param role the role - * @param element - * @param permissions - */ - boolean revokeRolePermissions(HibRole role, HibBaseElement element, InternalPermission... permissions); - - /** - * Create a new role - * - * @param ac - * @param batch - * @param uuid - * Uuid of the role - * @return - */ - default HibRole create(InternalActionContext ac, EventQueueBatch batch, String uuid) { - RoleCreateRequest requestModel = ac.fromJson(RoleCreateRequest.class); - String roleName = requestModel.getName(); - UserDao userDao = Tx.get().userDao(); - HibBaseElement roleRoot = Tx.get().data().permissionRoots().role(); - - HibUser requestUser = ac.getUser(); - if (StringUtils.isEmpty(roleName)) { - throw error(BAD_REQUEST, "error_name_must_be_set"); - } - - HibRole conflictingRole = findByName(roleName); - if (conflictingRole != null) { - throw conflict(conflictingRole.getUuid(), roleName, "role_conflicting_name"); - } - - if (!userDao.hasPermission(requestUser, roleRoot, CREATE_PERM)) { - throw error(FORBIDDEN, "error_missing_perm", roleRoot.getUuid(), CREATE_PERM.getRestPerm().getName()); - } - - HibRole role = create(requestModel.getName(), requestUser, uuid); - userDao.inheritRolePermissions(requestUser, roleRoot, role); - batch.add(role.onCreated()); - return role; - } - - @Override - default boolean grantPermissions(HibRole role, HibBaseElement element, InternalPermission... permissions) { - boolean permissionsGranted = grantRolePermissions(role, element, permissions); - if (permissionsGranted) { - PermissionCache cache = Tx.get().permissionCache(); - cache.clear(); - } - return permissionsGranted; - } - - /** - * Revoke the given permissions and clear the cache when successful - * - * @param role - * @param element - * @param permissions - * @return - */ - default boolean revokePermissions(HibRole role, HibBaseElement element, InternalPermission... permissions) { - boolean permissionsRevoked = revokeRolePermissions(role, element, permissions); - if (permissionsRevoked) { - PermissionCache cache = Tx.get().permissionCache(); - cache.clear(); - } - return permissionsRevoked; - } - - @Override - default void delete(HibRole role, BulkActionContext bac) { - bac.add(role.onDeleted()); - deletePersisted(role); - bac.process(); - PermissionCache permissionCache = Tx.get().permissionCache(); - - permissionCache.clear(); - } - - @Override + /** + * Grant role permission. Consumers implementing this method do not need to invalidate the cache + * @param role the role + * @param element + * @param permissions + */ + boolean grantRolePermissions(HibRole role, HibBaseElement element, InternalPermission... permissions); + + /** + * Grant the given permissions on the element to the set of roles. Implementations do not need to invalidate the cache + * + * @param roles set of roles + * @param element element to grant permission on + * @param exclusive true to revoke the given permissions on all other roles + * @param permissions permissions to grant + * @return true, iff permissions were effectively changed + */ + boolean grantRolePermissions(Set roles, HibBaseElement element, boolean exclusive, + InternalPermission... permissions); + + /** + * Revoke role permission. Consumers implementing this method do not need to invalidate the cache + * @param role the role + * @param element + * @param permissions + */ + boolean revokeRolePermissions(HibRole role, HibBaseElement element, InternalPermission... permissions); + + /** + * Revoke role permission. Consumers implementing this method do not need to invalidate the cache + * @param roles set of roles + * @param element element to revoke permissions from + * @param permissions permissions to revoke + * @return true, iff permissions were effectively changed + */ + boolean revokeRolePermissions(Set roles, HibBaseElement element, InternalPermission... permissions); + + /** + * Create a new role + * + * @param ac + * @param batch + * @param uuid + * Uuid of the role + * @return + */ + default HibRole create(InternalActionContext ac, EventQueueBatch batch, String uuid) { + RoleCreateRequest requestModel = ac.fromJson(RoleCreateRequest.class); + String roleName = requestModel.getName(); + UserDao userDao = Tx.get().userDao(); + HibBaseElement roleRoot = Tx.get().data().permissionRoots().role(); + + HibUser requestUser = ac.getUser(); + if (StringUtils.isEmpty(roleName)) { + throw error(BAD_REQUEST, "error_name_must_be_set"); + } + + HibRole conflictingRole = findByName(roleName); + if (conflictingRole != null) { + throw conflict(conflictingRole.getUuid(), roleName, "role_conflicting_name"); + } + + if (!userDao.hasPermission(requestUser, roleRoot, CREATE_PERM)) { + throw error(FORBIDDEN, "error_missing_perm", roleRoot.getUuid(), CREATE_PERM.getRestPerm().getName()); + } + + HibRole role = create(requestModel.getName(), requestUser, uuid); + userDao.inheritRolePermissions(requestUser, roleRoot, role); + batch.add(role.onCreated()); + return role; + } + + @Override + default boolean grantPermissions(HibRole role, HibBaseElement element, InternalPermission... permissions) { + boolean permissionsGranted = grantRolePermissions(role, element, permissions); + if (permissionsGranted) { + PermissionCache cache = Tx.get().permissionCache(); + cache.clear(); + } + return permissionsGranted; + } + + @Override + default boolean grantPermissions(Set roles, HibBaseElement element, boolean exclusive, + InternalPermission... permissions) { + boolean permissionsGranted = grantRolePermissions(roles, element, exclusive, permissions); + if (permissionsGranted) { + PermissionCache cache = Tx.get().permissionCache(); + cache.clear(); + } + return permissionsGranted; + } + + /** + * Revoke the given permissions and clear the cache when successful + * + * @param role + * @param element + * @param permissions + * @return + */ + default boolean revokePermissions(HibRole role, HibBaseElement element, InternalPermission... permissions) { + boolean permissionsRevoked = revokeRolePermissions(role, element, permissions); + if (permissionsRevoked) { + PermissionCache cache = Tx.get().permissionCache(); + cache.clear(); + } + return permissionsRevoked; + } + + @Override + default boolean revokePermissions(Set roles, HibBaseElement element, InternalPermission... permissions) { + boolean permissionsRevoked = revokeRolePermissions(roles, element, permissions); + if (permissionsRevoked) { + PermissionCache cache = Tx.get().permissionCache(); + cache.clear(); + } + return permissionsRevoked; + } + + @Override + default void delete(HibRole role, BulkActionContext bac) { + bac.add(role.onDeleted()); + deletePersisted(role); + bac.process(); + PermissionCache permissionCache = Tx.get().permissionCache(); + + permissionCache.clear(); + } + + @Override default Result getRolesWithPerm(HibBaseElement element, InternalPermission perm) { Set roleUuids = getRoleUuidsForPerm(element, perm); Stream stream = roleUuids == null @@ -141,7 +187,7 @@ default Result getRolesWithPerm(HibBaseElement element, Inter .filter(Objects::nonNull)); } - @Override + @Override default PermissionInfo getRolePermissions(HibBaseElement element, InternalActionContext ac, String roleUuid) { if (!isEmpty(roleUuid)) { HibRole role = loadObjectByUuid(ac, roleUuid, READ_PERM); @@ -218,6 +264,30 @@ default Set getPermissions(HibRole role, HibBaseElement elem return permissions; } + @Override + default Map> getPermissions(Set roles, HibBaseElement element) { + if (CollectionUtils.isEmpty(roles)) { + return Collections.emptyMap(); + } + Map> permissionsMap = new HashMap<>(); + InternalPermission[] possiblePermissions = element.hasPublishPermissions() + ? InternalPermission.values() + : InternalPermission.basicPermissions(); + + for (InternalPermission permission : possiblePermissions) { + Set allowedUuids = getRoleUuidsForPerm(element, permission); + for (HibRole role : roles) { + Set permissions = permissionsMap.computeIfAbsent(role, key -> new HashSet<>()); + + if (allowedUuids != null && allowedUuids.contains(role.getUuid())) { + permissions.add(permission); + } + } + } + + return permissionsMap; + } + @Override default RoleResponse transformToRestSync(HibRole role, InternalActionContext ac, int level, String... languageTags) { GenericParameters generic = ac.getGenericParameters(); diff --git a/mdm/common/src/main/java/com/gentics/mesh/example/RoleExamples.java b/mdm/common/src/main/java/com/gentics/mesh/example/RoleExamples.java index aab7532a93..d78831c060 100644 --- a/mdm/common/src/main/java/com/gentics/mesh/example/RoleExamples.java +++ b/mdm/common/src/main/java/com/gentics/mesh/example/RoleExamples.java @@ -12,15 +12,22 @@ import static com.gentics.mesh.example.ExampleUuids.ROLE_CLIENT_UUID; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import com.gentics.mesh.core.rest.Examples; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.group.GroupReference; import com.gentics.mesh.core.rest.role.RoleCreateRequest; import com.gentics.mesh.core.rest.role.RoleListResponse; import com.gentics.mesh.core.rest.role.RolePermissionRequest; import com.gentics.mesh.core.rest.role.RolePermissionResponse; +import com.gentics.mesh.core.rest.role.RoleReference; import com.gentics.mesh.core.rest.role.RoleResponse; import com.gentics.mesh.core.rest.role.RoleUpdateRequest; +import com.gentics.mesh.util.UUIDUtil; public class RoleExamples extends AbstractExamples { @@ -95,4 +102,56 @@ public RoleCreateRequest getRoleCreateRequest(String name) { return roleCreate; } + public ObjectPermissionResponse getObjectPermissionResponse(boolean includePublishPermissions) { + ObjectPermissionResponse response = new ObjectPermissionResponse(); + RoleReference role1 = Examples.roleRef(); + RoleReference role2 = Examples.roleRef2(); + + response.setCreate(Arrays.asList(role2)); + response.setRead(Arrays.asList(role1, role2)); + response.setUpdate(Arrays.asList(role1, role2)); + response.setDelete(Arrays.asList(role2)); + if (includePublishPermissions) { + response.setReadPublished(Arrays.asList(role1, role2)); + response.setPublish(Arrays.asList(role2)); + } + + response.setOthers(includePublishPermissions); + return response; + } + + public ObjectPermissionGrantRequest getObjectPermissionGrantRequest(boolean includePublishPermissions) { + ObjectPermissionGrantRequest request = new ObjectPermissionGrantRequest(); + RoleReference role1 = Examples.roleRef(); + RoleReference role2 = Examples.roleRef2(); + RoleReference adminRef = new RoleReference().setName("admin").setUuid(UUIDUtil.randomUUID()); + + request.setCreate(Arrays.asList(role2)); + request.setRead(Arrays.asList(role1, role2)); + request.setUpdate(Arrays.asList(role1, role2)); + request.setDelete(Arrays.asList(role2)); + if (includePublishPermissions) { + request.setReadPublished(Arrays.asList(role1, role2)); + request.setPublish(Arrays.asList(role2)); + } + request.setExclusive(true); + request.setIgnore(Arrays.asList(adminRef)); + return request; + } + + public ObjectPermissionRevokeRequest getObjectPermissionRevokeRequest(boolean includePublishPermissions) { + ObjectPermissionRevokeRequest request = new ObjectPermissionRevokeRequest(); + RoleReference role1 = Examples.roleRef(); + RoleReference role2 = Examples.roleRef2(); + + request.setCreate(Arrays.asList(role2)); + request.setRead(Arrays.asList(role1, role2)); + request.setUpdate(Arrays.asList(role1, role2)); + request.setDelete(Arrays.asList(role2)); + if (includePublishPermissions) { + request.setReadPublished(Arrays.asList(role1, role2)); + request.setPublish(Arrays.asList(role2)); + } + return request; + } } diff --git a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/RoleDaoWrapperImpl.java b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/RoleDaoWrapperImpl.java index 0b8c364a91..5d601b797d 100644 --- a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/RoleDaoWrapperImpl.java +++ b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/RoleDaoWrapperImpl.java @@ -5,6 +5,7 @@ import java.util.Collections; import java.util.Set; import java.util.function.Predicate; +import java.util.stream.Collectors; import javax.inject.Inject; import javax.inject.Singleton; @@ -57,6 +58,34 @@ public boolean grantRolePermissions(HibRole role, HibBaseElement element, Intern return permissionGranted; } + @Override + public boolean grantRolePermissions(Set roles, HibBaseElement element, boolean exclusive, + InternalPermission... permissions) { + MeshVertex vertex = (MeshVertex) element; + boolean permissionGranted = false; + Set roleUuids = roles.stream().map(HibRole::getUuid).collect(Collectors.toSet()); + + for (InternalPermission permission : permissions) { + Set allowedRoles = getRoleUuidsForPerm(vertex, permission); + + if (allowedRoles == null) { + vertex.setRoleUuidForPerm(permission, roleUuids); + if (!roleUuids.isEmpty()) { + permissionGranted = true; + } + } else { + permissionGranted = allowedRoles.addAll(roleUuids) || permissionGranted; + if (exclusive) { + permissionGranted = allowedRoles.retainAll(roleUuids) || permissionGranted; + } + + vertex.setRoleUuidForPerm(permission, allowedRoles); + } + } + + return permissionGranted; + } + @Override public boolean revokeRolePermissions(HibRole role, HibBaseElement element, InternalPermission... permissions) { MeshVertex vertex = (MeshVertex) element; @@ -72,6 +101,24 @@ public boolean revokeRolePermissions(HibRole role, HibBaseElement element, Inter return permissionRevoked; } + @Override + public boolean revokeRolePermissions(Set roles, HibBaseElement element, InternalPermission... permissions) { + MeshVertex vertex = (MeshVertex) element; + + boolean permissionRevoked = false; + for (InternalPermission permission : permissions) { + Set allowedRoles = getRoleUuidsForPerm(vertex, permission); + if (allowedRoles != null) { + for (HibRole role : roles) { + permissionRevoked = allowedRoles.remove(role.getUuid()) || permissionRevoked; + } + vertex.setRoleUuidForPerm(permission, allowedRoles); + } + } + + return permissionRevoked; + } + @Override public HibRole findByUuid(String uuid) { RoleRoot roleRoot = boot.get().meshRoot().getRoleRoot(); diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshRestHttpClientImpl.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshRestHttpClientImpl.java index 19b95c4040..98e7b2fb31 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshRestHttpClientImpl.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshRestHttpClientImpl.java @@ -35,6 +35,9 @@ import com.gentics.mesh.core.rest.branch.info.BranchInfoMicroschemaList; import com.gentics.mesh.core.rest.branch.info.BranchInfoSchemaList; import com.gentics.mesh.core.rest.common.GenericMessageResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.common.RestModel; import com.gentics.mesh.core.rest.graphql.GraphQLRequest; import com.gentics.mesh.core.rest.graphql.GraphQLResponse; @@ -1662,4 +1665,244 @@ public MeshRequest webrootField(String projectName, St return prepareRequest(GET, "/" + encodeSegment(projectName) + "/webrootfield/" + fieldName + path + getQuery(parameters), MeshWebrootFieldResponse.class); } + + @Override + public MeshRequest getBranchRolePermissions(String projectName, String uuid) { + Objects.requireNonNull(projectName, "projectName must not be null"); + Objects.requireNonNull(uuid, "uuid must not be null"); + return prepareRequest(GET, "/" + encodeSegment(projectName) + "/branches/" + uuid + "/rolePermissions", + ObjectPermissionResponse.class); + } + + @Override + public MeshRequest grantBranchRolePermissions(String projectName, String uuid, + ObjectPermissionGrantRequest request) { + Objects.requireNonNull(projectName, "projectName must not be null"); + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(POST, "/" + encodeSegment(projectName) + "/branches/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest revokeBranchRolePermissions(String projectName, String uuid, + ObjectPermissionRevokeRequest request) { + Objects.requireNonNull(projectName, "projectName must not be null"); + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(DELETE, "/" + encodeSegment(projectName) + "/branches/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest getGroupRolePermissions(String uuid) { + Objects.requireNonNull(uuid, "uuid must not be null"); + return prepareRequest(GET, "/groups/" + uuid + "/rolePermissions", ObjectPermissionResponse.class); + } + + @Override + public MeshRequest grantGroupRolePermissions(String uuid, + ObjectPermissionGrantRequest request) { + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(POST, "/groups/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest revokeGroupRolePermissions(String uuid, + ObjectPermissionRevokeRequest request) { + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(DELETE, "/groups/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest getMicroschemaRolePermissions(String uuid) { + Objects.requireNonNull(uuid, "uuid must not be null"); + return prepareRequest(GET, "/microschemas/" + uuid + "/rolePermissions", ObjectPermissionResponse.class); + } + + @Override + public MeshRequest grantMicroschemaRolePermissions(String uuid, + ObjectPermissionGrantRequest request) { + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(POST, "/microschemas/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest revokeMicroschemaRolePermissions(String uuid, + ObjectPermissionRevokeRequest request) { + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(DELETE, "/microschemas/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest getNodeRolePermissions(String projectName, String uuid) { + Objects.requireNonNull(projectName, "projectName must not be null"); + Objects.requireNonNull(uuid, "uuid must not be null"); + return prepareRequest(GET, "/" + encodeSegment(projectName) + "/nodes/" + uuid + "/rolePermissions", + ObjectPermissionResponse.class); + } + + @Override + public MeshRequest grantNodeRolePermissions(String projectName, String uuid, + ObjectPermissionGrantRequest request) { + Objects.requireNonNull(projectName, "projectName must not be null"); + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(POST, "/" + encodeSegment(projectName) + "/nodes/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest revokeNodeRolePermissions(String projectName, String uuid, + ObjectPermissionRevokeRequest request) { + Objects.requireNonNull(projectName, "projectName must not be null"); + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(DELETE, "/" + encodeSegment(projectName) + "/nodes/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest getProjectRolePermissions(String uuid) { + Objects.requireNonNull(uuid, "uuid must not be null"); + return prepareRequest(GET, "/projects/" + uuid + "/rolePermissions", ObjectPermissionResponse.class); + } + + @Override + public MeshRequest grantProjectRolePermissions(String uuid, + ObjectPermissionGrantRequest request) { + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(POST, "/projects/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest revokeProjectRolePermissions(String uuid, + ObjectPermissionRevokeRequest request) { + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(DELETE, "/projects/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest getRoleRolePermissions(String uuid) { + Objects.requireNonNull(uuid, "uuid must not be null"); + return prepareRequest(GET, "/roles/" + uuid + "/rolePermissions", ObjectPermissionResponse.class); + } + + @Override + public MeshRequest grantRoleRolePermissions(String uuid, + ObjectPermissionGrantRequest request) { + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(POST, "/roles/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest revokeRoleRolePermissions(String uuid, + ObjectPermissionRevokeRequest request) { + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(DELETE, "/roles/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest getSchemaRolePermissions(String uuid) { + Objects.requireNonNull(uuid, "uuid must not be null"); + return prepareRequest(GET, "/schemas/" + uuid + "/rolePermissions", ObjectPermissionResponse.class); + } + + @Override + public MeshRequest grantSchemaRolePermissions(String uuid, + ObjectPermissionGrantRequest request) { + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(POST, "/schemas/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest revokeSchemaRolePermissions(String uuid, + ObjectPermissionRevokeRequest request) { + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(DELETE, "/schemas/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest getTagFamilyRolePermissions(String projectName, String tagFamilyUuid) { + Objects.requireNonNull(projectName, "projectName must not be null"); + Objects.requireNonNull(tagFamilyUuid, "tagFamilyUuid must not be null"); + return prepareRequest(GET, "/" + encodeSegment(projectName) + "/tagFamilies/" + tagFamilyUuid + "/rolePermissions", + ObjectPermissionResponse.class); + } + + @Override + public MeshRequest grantTagFamilyRolePermissions(String projectName, String tagFamilyUuid, + ObjectPermissionGrantRequest request) { + Objects.requireNonNull(projectName, "projectName must not be null"); + Objects.requireNonNull(tagFamilyUuid, "tagFamilyUuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(POST, "/" + encodeSegment(projectName) + "/tagFamilies/" + tagFamilyUuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest revokeTagFamilyRolePermissions(String projectName, String tagFamilyUuid, + ObjectPermissionRevokeRequest request) { + Objects.requireNonNull(projectName, "projectName must not be null"); + Objects.requireNonNull(tagFamilyUuid, "tagFamilyUuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(DELETE, "/" + encodeSegment(projectName) + "/tagFamilies/" + tagFamilyUuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest getTagRolePermissions(String projectName, String tagFamilyUuid, + String uuid) { + Objects.requireNonNull(projectName, "projectName must not be null"); + Objects.requireNonNull(tagFamilyUuid, "tagFamilyUuid must not be null"); + Objects.requireNonNull(uuid, "uuid must not be null"); + return prepareRequest(GET, "/" + encodeSegment(projectName) + "/tagFamilies/" + tagFamilyUuid + "/tags/" + uuid + "/rolePermissions", + ObjectPermissionResponse.class); + } + + @Override + public MeshRequest grantTagRolePermissions(String projectName, String tagFamilyUuid, String uuid, + ObjectPermissionGrantRequest request) { + Objects.requireNonNull(projectName, "projectName must not be null"); + Objects.requireNonNull(tagFamilyUuid, "tagFamilyUuid must not be null"); + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(POST, "/" + encodeSegment(projectName) + "/tagFamilies/" + tagFamilyUuid + "/tags/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest revokeTagRolePermissions(String projectName, String tagFamilyUuid, String uuid, + ObjectPermissionRevokeRequest request) { + Objects.requireNonNull(projectName, "projectName must not be null"); + Objects.requireNonNull(tagFamilyUuid, "tagFamilyUuid must not be null"); + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(DELETE, "/" + encodeSegment(projectName) + "/tagFamilies/" + tagFamilyUuid + "/tags/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest getUserRolePermissions(String uuid) { + Objects.requireNonNull(uuid, "uuid must not be null"); + return prepareRequest(GET, "/users/" + uuid + "/rolePermissions", ObjectPermissionResponse.class); + } + + @Override + public MeshRequest grantUserRolePermissions(String uuid, + ObjectPermissionGrantRequest request) { + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(POST, "/users/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } + + @Override + public MeshRequest revokeUserRolePermissions(String uuid, + ObjectPermissionRevokeRequest request) { + Objects.requireNonNull(uuid, "uuid must not be null"); + Objects.requireNonNull(request, "objectPermissionRequest must not be null"); + return prepareRequest(DELETE, "/users/" + uuid + "/rolePermissions", ObjectPermissionResponse.class, request); + } } diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/BranchClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/BranchClientMethods.java index 536631ed17..46906da38a 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/BranchClientMethods.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/BranchClientMethods.java @@ -7,6 +7,9 @@ import com.gentics.mesh.core.rest.branch.info.BranchInfoMicroschemaList; import com.gentics.mesh.core.rest.branch.info.BranchInfoSchemaList; import com.gentics.mesh.core.rest.common.GenericMessageResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.schema.MicroschemaReference; import com.gentics.mesh.core.rest.schema.SchemaReference; import com.gentics.mesh.core.rest.tag.TagListResponse; @@ -206,4 +209,35 @@ MeshRequest assignBranchMicroschemaVersions(String pr */ MeshRequest updateTagsForBranch(String projectName, String branchUuid, TagListUpdateRequest request); + /** + * Get the role permissions on the branch + * + * @param projectName + * Name of the project + * @param uuid Uuid of the branch + * @return request + */ + MeshRequest getBranchRolePermissions(String projectName, String uuid); + + /** + * Grant permissions on the branch to roles + * + * @param projectName + * Name of the project + * @param uuid Uuid of the branch + * @param request request + * @return mesh request + */ + MeshRequest grantBranchRolePermissions(String projectName, String uuid, ObjectPermissionGrantRequest request); + + /** + * Revoke permissions on the branch from roles + * + * @param projectName + * Name of the project + * @param uuid Uuid of the branch + * @param request request + * @return mesh request + */ + MeshRequest revokeBranchRolePermissions(String projectName, String uuid, ObjectPermissionRevokeRequest request); } diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/GroupClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/GroupClientMethods.java index 0a08ec3353..fdae5c62e7 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/GroupClientMethods.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/GroupClientMethods.java @@ -1,5 +1,8 @@ package com.gentics.mesh.rest.client.method; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.group.GroupCreateRequest; import com.gentics.mesh.core.rest.group.GroupListResponse; import com.gentics.mesh.core.rest.group.GroupResponse; @@ -100,4 +103,27 @@ public interface GroupClientMethods { */ MeshRequest removeRoleFromGroup(String groupUuid, String roleUuid); + /** + * Get the role permissions on the group + * + * @param uuid Uuid of the group + * @return request + */ + MeshRequest getGroupRolePermissions(String uuid); + + /** + * Grant permissions on the group to roles + * @param uuid Uuid of the group + * @param request request + * @return mesh request + */ + MeshRequest grantGroupRolePermissions(String uuid, ObjectPermissionGrantRequest request); + + /** + * Revoke permissions on the group from roles + * @param uuid Uuid of the group + * @param request request + * @return mesh request + */ + MeshRequest revokeGroupRolePermissions(String uuid, ObjectPermissionRevokeRequest request); } diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/MicroschemaClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/MicroschemaClientMethods.java index 7c2853adec..08e95c87cc 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/MicroschemaClientMethods.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/MicroschemaClientMethods.java @@ -1,6 +1,9 @@ package com.gentics.mesh.rest.client.method; import com.gentics.mesh.core.rest.common.GenericMessageResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.microschema.impl.MicroschemaCreateRequest; import com.gentics.mesh.core.rest.microschema.impl.MicroschemaResponse; import com.gentics.mesh.core.rest.microschema.impl.MicroschemaUpdateRequest; @@ -83,4 +86,27 @@ public interface MicroschemaClientMethods { */ MeshRequest diffMicroschema(String uuid, MicroschemaModel request); + /** + * Get the role permissions on the microschema + * + * @param uuid Uuid of the microschema + * @return request + */ + MeshRequest getMicroschemaRolePermissions(String uuid); + + /** + * Grant permissions on the microschema to roles + * @param uuid Uuid of the microschema + * @param request request + * @return mesh request + */ + MeshRequest grantMicroschemaRolePermissions(String uuid, ObjectPermissionGrantRequest request); + + /** + * Revoke permissions on the microschema from roles + * @param uuid Uuid of the microschema + * @param request request + * @return mesh request + */ + MeshRequest revokeMicroschemaRolePermissions(String uuid, ObjectPermissionRevokeRequest request); } diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/NodeClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/NodeClientMethods.java index 280e041c3e..2918aaa221 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/NodeClientMethods.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/NodeClientMethods.java @@ -1,5 +1,8 @@ package com.gentics.mesh.rest.client.method; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.node.NodeCreateRequest; import com.gentics.mesh.core.rest.node.NodeListResponse; import com.gentics.mesh.core.rest.node.NodeResponse; @@ -301,4 +304,35 @@ default MeshRequest takeNodeLanguage(String projectName, String n */ MeshRequest listNodeVersions(String projectName, String nodeUuid, ParameterProvider...parameters); + /** + * Get the role permissions on the node + * + * @param projectName + * Name of the project + * @param uuid Uuid of the node + * @return request + */ + MeshRequest getNodeRolePermissions(String projectName, String uuid); + + /** + * Grant permissions on the node to roles + * + * @param projectName + * Name of the project + * @param uuid Uuid of the node + * @param request request + * @return mesh request + */ + MeshRequest grantNodeRolePermissions(String projectName, String uuid, ObjectPermissionGrantRequest request); + + /** + * Revoke permissions on the node from roles + * + * @param projectName + * Name of the project + * @param uuid Uuid of the node + * @param request request + * @return mesh request + */ + MeshRequest revokeNodeRolePermissions(String projectName, String uuid, ObjectPermissionRevokeRequest request); } diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/ProjectClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/ProjectClientMethods.java index ef6060a909..9277f4f9a2 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/ProjectClientMethods.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/ProjectClientMethods.java @@ -1,6 +1,9 @@ package com.gentics.mesh.rest.client.method; import com.gentics.mesh.core.rest.common.GenericMessageResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.project.ProjectCreateRequest; import com.gentics.mesh.core.rest.project.ProjectListResponse; import com.gentics.mesh.core.rest.project.ProjectResponse; @@ -103,4 +106,28 @@ public interface ProjectClientMethods { * @return */ MeshRequest purgeProject(String uuid, ParameterProvider... parameters); + + /** + * Get the role permissions on the project + * + * @param uuid Uuid of the project + * @return request + */ + MeshRequest getProjectRolePermissions(String uuid); + + /** + * Grant permissions on the project to roles + * @param uuid Uuid of the project + * @param request request + * @return mesh request + */ + MeshRequest grantProjectRolePermissions(String uuid, ObjectPermissionGrantRequest request); + + /** + * Revoke permissions on the project from roles + * @param uuid Uuid of the project + * @param request request + * @return mesh request + */ + MeshRequest revokeProjectRolePermissions(String uuid, ObjectPermissionRevokeRequest request); } diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/RoleClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/RoleClientMethods.java index b99d00fe93..b65478a8ad 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/RoleClientMethods.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/RoleClientMethods.java @@ -1,6 +1,9 @@ package com.gentics.mesh.rest.client.method; import com.gentics.mesh.core.rest.common.GenericMessageResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.role.RoleCreateRequest; import com.gentics.mesh.core.rest.role.RoleListResponse; import com.gentics.mesh.core.rest.role.RolePermissionRequest; @@ -99,4 +102,29 @@ public interface RoleClientMethods { * @return */ MeshRequest updateRole(String uuid, RoleUpdateRequest restRole); + + /** + * Get the role permissions on the role + * + * @param uuid + * Uuid of the role + * @return request + */ + MeshRequest getRoleRolePermissions(String uuid); + + /** + * Grant permissions on the role to roles + * @param uuid Uuid of the role + * @param request request + * @return mesh request + */ + MeshRequest grantRoleRolePermissions(String uuid, ObjectPermissionGrantRequest request); + + /** + * Revoke permissions on the role from roles + * @param uuid Uuid of the role + * @param request request + * @return mesh request + */ + MeshRequest revokeRoleRolePermissions(String uuid, ObjectPermissionRevokeRequest request); } diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/SchemaClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/SchemaClientMethods.java index 2ee24cb95a..50519357e2 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/SchemaClientMethods.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/SchemaClientMethods.java @@ -1,6 +1,9 @@ package com.gentics.mesh.rest.client.method; import com.gentics.mesh.core.rest.common.GenericMessageResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.microschema.impl.MicroschemaResponse; import com.gentics.mesh.core.rest.schema.MicroschemaListResponse; import com.gentics.mesh.core.rest.schema.SchemaListResponse; @@ -169,4 +172,28 @@ public interface SchemaClientMethods { * @return */ MeshRequest findMicroschemas(String projectName, ParameterProvider... parameters); + + /** + * Get the role permissions on the schema + * + * @param uuid Uuid of the schema + * @return request + */ + MeshRequest getSchemaRolePermissions(String uuid); + + /** + * Grant permissions on the schema to roles + * @param uuid Uuid of the schema + * @param request request + * @return mesh request + */ + MeshRequest grantSchemaRolePermissions(String uuid, ObjectPermissionGrantRequest request); + + /** + * Revoke permissions on the schema from roles + * @param uuid Uuid of the schema + * @param request request + * @return mesh request + */ + MeshRequest revokeSchemaRolePermissions(String uuid, ObjectPermissionRevokeRequest request); } diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagClientMethods.java index 62bb40584f..f57da8ba48 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagClientMethods.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagClientMethods.java @@ -1,5 +1,8 @@ package com.gentics.mesh.rest.client.method; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.tag.TagCreateRequest; import com.gentics.mesh.core.rest.tag.TagListResponse; import com.gentics.mesh.core.rest.tag.TagResponse; @@ -90,4 +93,39 @@ public interface TagClientMethods { */ MeshRequest findTags(String projectName, String tagFamilyUuid, ParameterProvider... parameters); + /** + * Get the role permissions on the tag + * + * @param projectName + * Name of the project + * @param tagFamilyUuid + * Uuid of the tagfamily in which the tag is stored + * @param uuid Uuid of the tag + * @return request + */ + MeshRequest getTagRolePermissions(String projectName, String tagFamilyUuid, String uuid); + + /** + * Grant permissions on the tag to roles + * @param projectName + * Name of the project + * @param tagFamilyUuid + * Uuid of the tagfamily in which the tag is stored + * @param uuid Uuid of the tag + * @param request request + * @return mesh request + */ + MeshRequest grantTagRolePermissions(String projectName, String tagFamilyUuid, String uuid, ObjectPermissionGrantRequest request); + + /** + * Revoke permissions on the tag from roles + * @param projectName + * Name of the project + * @param tagFamilyUuid + * Uuid of the tagfamily in which the tag is stored + * @param uuid Uuid of the tag + * @param request request + * @return mesh request + */ + MeshRequest revokeTagRolePermissions(String projectName, String tagFamilyUuid, String uuid, ObjectPermissionRevokeRequest request); } diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagFamilyClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagFamilyClientMethods.java index 49c79972a6..bf6e9d3bfa 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagFamilyClientMethods.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/TagFamilyClientMethods.java @@ -1,5 +1,8 @@ package com.gentics.mesh.rest.client.method; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.tag.TagFamilyCreateRequest; import com.gentics.mesh.core.rest.tag.TagFamilyListResponse; import com.gentics.mesh.core.rest.tag.TagFamilyResponse; @@ -91,5 +94,38 @@ public interface TagFamilyClientMethods { */ MeshRequest findTagFamilies(String projectName, ParameterProvider... parameters); + /** + * Get the role permissions on the tag family + * + * @param projectName + * Name of the project + * @param tagFamilyUuid + * Uuid of the tagfamily + * @return request + */ + MeshRequest getTagFamilyRolePermissions(String projectName, String tagFamilyUuid); + + /** + * Grant permissions on the tag family to roles + * + * @param projectName + * Name of the project + * @param tagFamilyUuid + * Uuid of the tagfamily + * @param request request + * @return mesh request + */ + MeshRequest grantTagFamilyRolePermissions(String projectName, String tagFamilyUuid, ObjectPermissionGrantRequest request); + /** + * Revoke permissions on the tag family from roles + * + * @param projectName + * Name of the project + * @param tagFamilyUuid + * Uuid of the tagfamily + * @param request request + * @return mesh request + */ + MeshRequest revokeTagFamilyRolePermissions(String projectName, String tagFamilyUuid, ObjectPermissionRevokeRequest request); } diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/UserClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/UserClientMethods.java index f18ee71bde..07f3ee83c7 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/UserClientMethods.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/UserClientMethods.java @@ -1,6 +1,9 @@ package com.gentics.mesh.rest.client.method; import com.gentics.mesh.core.rest.common.GenericMessageResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; import com.gentics.mesh.core.rest.user.UserAPITokenResponse; import com.gentics.mesh.core.rest.user.UserCreateRequest; import com.gentics.mesh.core.rest.user.UserListResponse; @@ -119,4 +122,28 @@ public interface UserClientMethods { * @return */ MeshRequest invalidateAPIToken(String userUuid); + + /** + * Get the role permissions on the user + * + * @param uuid Uuid of the user + * @return request + */ + MeshRequest getUserRolePermissions(String uuid); + + /** + * Grant permissions on the user to roles + * @param uuid Uuid of the user + * @param request request + * @return mesh request + */ + MeshRequest grantUserRolePermissions(String uuid, ObjectPermissionGrantRequest request); + + /** + * Revoke permissions on the user from roles + * @param uuid Uuid of the user + * @param request request + * @return mesh request + */ + MeshRequest revokeUserRolePermissions(String uuid, ObjectPermissionRevokeRequest request); } diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/Examples.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/Examples.java index d353d4c4a9..1def6709eb 100644 --- a/rest-model/src/main/java/com/gentics/mesh/core/rest/Examples.java +++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/Examples.java @@ -276,6 +276,13 @@ public static RoleReference roleRef() { return ref; } + public static RoleReference roleRef2() { + RoleReference ref = new RoleReference(); + ref.setUuid(uuid5()); + ref.setName("editor"); + return ref; + } + public static TagReference tagRef() { String uuid = "e5861ba26b914b21861ba26b91ab211a"; TagReference ref = new TagReference(); @@ -321,4 +328,8 @@ public static String uuid4() { return "d84a6f054a3f4ed68a6f054a3f1ed635"; } + public static String uuid5() { + return "01ed2f8647421b2b85891e5204d53f1b"; + } + } diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/common/ObjectPermissionGrantRequest.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/ObjectPermissionGrantRequest.java new file mode 100644 index 0000000000..94de790646 --- /dev/null +++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/ObjectPermissionGrantRequest.java @@ -0,0 +1,98 @@ +package com.gentics.mesh.core.rest.common; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.gentics.mesh.core.rest.role.RoleReference; + +/** + * Request to grant permissions to multiple roles + */ +public class ObjectPermissionGrantRequest extends ObjectPermissionResponse { + @JsonProperty(required = false, defaultValue = "false") + @JsonPropertyDescription("Flag which indicates whether the permissions granted to only the given roles (will be revoked from all other roles).") + private boolean exclusive = false; + + @JsonProperty(required = true) + @JsonPropertyDescription("Roles which are ignored when the exclusive flag is set.") + private List ignore; + + /** + * Flag that indicated that the request should be executed exclusively. + * + * @return Flag value + */ + public boolean isExclusive() { + return exclusive; + } + + /** + * Set the flag which indicated whether the permission changes should be applied exclusively. + * + * @param exclusive + * Flag value + * @return Fluent API + */ + public ObjectPermissionGrantRequest setExclusive(boolean exclusive) { + this.exclusive = exclusive; + return this; + } + + public List getIgnore() { + return ignore; + } + + public ObjectPermissionGrantRequest setIgnore(List ignore) { + this.ignore = ignore; + return this; + } + + @Override + public ObjectPermissionGrantRequest setCreate(List create) { + super.setCreate(create); + return this; + } + + @Override + public ObjectPermissionGrantRequest setRead(List read) { + super.setRead(read); + return this; + } + + @Override + public ObjectPermissionGrantRequest setUpdate(List update) { + super.setUpdate(update); + return this; + } + + @Override + public ObjectPermissionGrantRequest setDelete(List delete) { + super.setDelete(delete); + return this; + } + + @Override + public ObjectPermissionGrantRequest setPublish(List publish) { + super.setPublish(publish); + return this; + } + + @Override + public ObjectPermissionGrantRequest setReadPublished(List readPublished) { + super.setReadPublished(readPublished); + return this; + } + + @Override + public ObjectPermissionGrantRequest add(RoleReference role, Permission permission) { + super.add(role, permission); + return this; + } + + @Override + public ObjectPermissionGrantRequest setOthers(boolean includePublishPermissions) { + super.setOthers(includePublishPermissions); + return this; + } +} diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/common/ObjectPermissionResponse.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/ObjectPermissionResponse.java new file mode 100644 index 0000000000..4745562a87 --- /dev/null +++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/ObjectPermissionResponse.java @@ -0,0 +1,189 @@ +package com.gentics.mesh.core.rest.common; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.gentics.mesh.core.rest.role.RoleReference; + +/** + * Response containing object permissions on all roles + */ +public class ObjectPermissionResponse implements RestModel { + @JsonProperty(required = true) + @JsonPropertyDescription("Roles to which the create permission is granted.") + private List create; + + @JsonProperty(required = true) + @JsonPropertyDescription("Roles to which the read permission is granted.") + private List read; + + @JsonProperty(required = true) + @JsonPropertyDescription("Roles to which the update permission is granted.") + private List update; + + @JsonProperty(required = true) + @JsonPropertyDescription("Roles to which the delete permission is granted.") + private List delete; + + @JsonProperty(required = false) + @JsonPropertyDescription("Roles to which the publish permission is granted.") + private List publish; + + @JsonProperty(required = false) + @JsonPropertyDescription("Roles to which the read published permission is granted.") + private List readPublished; + + public List getCreate() { + return create; + } + + public ObjectPermissionResponse setCreate(List create) { + this.create = create; + return this; + } + + public List getRead() { + return read; + } + + public ObjectPermissionResponse setRead(List read) { + this.read = read; + return this; + } + + public List getUpdate() { + return update; + } + + public ObjectPermissionResponse setUpdate(List update) { + this.update = update; + return this; + } + + public List getDelete() { + return delete; + } + + public ObjectPermissionResponse setDelete(List delete) { + this.delete = delete; + return this; + } + + public List getPublish() { + return publish; + } + + public ObjectPermissionResponse setPublish(List publish) { + this.publish = publish; + return this; + } + + public List getReadPublished() { + return readPublished; + } + + public ObjectPermissionResponse setReadPublished(List readPublished) { + this.readPublished = readPublished; + return this; + } + + /** + * Set the given permission. + * + * @param role role reference + * @param permission permission + * @return Fluent API + */ + public ObjectPermissionResponse add(RoleReference role, Permission permission) { + switch (permission) { + case CREATE: + create = add(create, role); + break; + case READ: + read = add(read, role); + break; + case UPDATE: + update = add(update, role); + break; + case DELETE: + delete = add(delete, role); + break; + case PUBLISH: + publish = add(publish, role); + break; + case READ_PUBLISHED: + readPublished = add(readPublished, role); + break; + default: + throw new RuntimeException("Unknown permission type {" + permission.getName() + "}"); + } + + return this; + } + + /** + * Set other permissions to empty sets + * + * @param includePublishPermissions + * @return Fluent API + */ + public ObjectPermissionResponse setOthers(boolean includePublishPermissions) { + if (create == null) { + create = Collections.emptyList(); + } + if (read == null) { + read = Collections.emptyList(); + } + if (update == null) { + update = Collections.emptyList(); + } + if (delete == null) { + delete = Collections.emptyList(); + } + if (includePublishPermissions) { + if (publish == null) { + publish = Collections.emptyList(); + } + if (readPublished == null) { + readPublished = Collections.emptyList(); + } + } + return this; + } + + /** + * Get the roles with the given permission + * @param perm permission + * @return set of role references + */ + public List get(Permission perm) { + switch (perm) { + case CREATE: + return create; + case READ: + return read; + case UPDATE: + return update; + case DELETE: + return delete; + case PUBLISH: + return publish; + case READ_PUBLISHED: + return readPublished; + default: + throw new RuntimeException("Unknown permission type {" + perm.getName() + "}"); + } + } + + protected List add(List set, RoleReference role) { + if (set == null) { + set = new ArrayList<>(); + } + set.add(role); + + return set; + } +} diff --git a/rest-model/src/main/java/com/gentics/mesh/core/rest/common/ObjectPermissionRevokeRequest.java b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/ObjectPermissionRevokeRequest.java new file mode 100644 index 0000000000..d6f9a8ad69 --- /dev/null +++ b/rest-model/src/main/java/com/gentics/mesh/core/rest/common/ObjectPermissionRevokeRequest.java @@ -0,0 +1,58 @@ +package com.gentics.mesh.core.rest.common; + +import java.util.List; + +import com.gentics.mesh.core.rest.role.RoleReference; + +/** + * Request to revoke permissions from multiple roles + */ +public class ObjectPermissionRevokeRequest extends ObjectPermissionResponse { + @Override + public ObjectPermissionRevokeRequest setCreate(List create) { + super.setCreate(create); + return this; + } + + @Override + public ObjectPermissionRevokeRequest setRead(List read) { + super.setRead(read); + return this; + } + + @Override + public ObjectPermissionRevokeRequest setUpdate(List update) { + super.setUpdate(update); + return this; + } + + @Override + public ObjectPermissionRevokeRequest setDelete(List delete) { + super.setDelete(delete); + return this; + } + + @Override + public ObjectPermissionRevokeRequest setPublish(List publish) { + super.setPublish(publish); + return this; + } + + @Override + public ObjectPermissionRevokeRequest setReadPublished(List readPublished) { + super.setReadPublished(readPublished); + return this; + } + + @Override + public ObjectPermissionRevokeRequest add(RoleReference role, Permission permission) { + super.add(role, permission); + return this; + } + + @Override + public ObjectPermissionRevokeRequest setOthers(boolean includePublishPermissions) { + super.setOthers(includePublishPermissions); + return this; + } +} diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/branch/BranchRolePermissionsEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/branch/BranchRolePermissionsEndpointTest.java new file mode 100644 index 0000000000..b05d072a21 --- /dev/null +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/branch/BranchRolePermissionsEndpointTest.java @@ -0,0 +1,39 @@ +package com.gentics.mesh.core.branch; + +import static com.gentics.mesh.test.TestDataProvider.PROJECT_NAME; +import static com.gentics.mesh.test.TestSize.FULL; + +import com.gentics.mesh.core.data.HibBaseElement; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; +import com.gentics.mesh.test.MeshTestSetting; +import com.gentics.mesh.test.context.AbstractRolePermissionEndpointTest; +import com.gentics.mesh.test.context.ClientHandler; + +/** + * Test cases for handling role permissions for branches + */ +@MeshTestSetting(testSize = FULL, startServer = true) +public class BranchRolePermissionsEndpointTest extends AbstractRolePermissionEndpointTest { + + @Override + protected HibBaseElement getTestedElement() { + return project().getInitialBranch(); + } + + @Override + protected ClientHandler getRolePermissions() { + return () -> client().getBranchRolePermissions(PROJECT_NAME, getTestedUuid()); + } + + @Override + protected ClientHandler grantRolePermissions(ObjectPermissionGrantRequest request) { + return () -> client().grantBranchRolePermissions(PROJECT_NAME, getTestedUuid(), request); + } + + @Override + protected ClientHandler revokeRolePermissions(ObjectPermissionRevokeRequest request) { + return () -> client().revokeBranchRolePermissions(PROJECT_NAME, getTestedUuid(), request); + } +} diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/group/GroupRolePermissionsEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/group/GroupRolePermissionsEndpointTest.java new file mode 100644 index 0000000000..0e32964bf8 --- /dev/null +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/group/GroupRolePermissionsEndpointTest.java @@ -0,0 +1,38 @@ +package com.gentics.mesh.core.group; + +import static com.gentics.mesh.test.TestSize.PROJECT_AND_NODE; + +import com.gentics.mesh.core.data.HibBaseElement; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; +import com.gentics.mesh.test.MeshTestSetting; +import com.gentics.mesh.test.context.AbstractRolePermissionEndpointTest; +import com.gentics.mesh.test.context.ClientHandler; + +/** + * Test cases for handling role permissions for groups + */ +@MeshTestSetting(testSize = PROJECT_AND_NODE, startServer = true) +public class GroupRolePermissionsEndpointTest extends AbstractRolePermissionEndpointTest { + + @Override + protected HibBaseElement getTestedElement() { + return group(); + } + + @Override + protected ClientHandler getRolePermissions() { + return () -> client().getGroupRolePermissions(getTestedUuid()); + } + + @Override + protected ClientHandler grantRolePermissions(ObjectPermissionGrantRequest request) { + return () -> client().grantGroupRolePermissions(getTestedUuid(), request); + } + + @Override + protected ClientHandler revokeRolePermissions(ObjectPermissionRevokeRequest request) { + return () -> client().revokeGroupRolePermissions(getTestedUuid(), request); + } +} diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/node/NodeRolePermissionsEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/node/NodeRolePermissionsEndpointTest.java new file mode 100644 index 0000000000..65114f4235 --- /dev/null +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/node/NodeRolePermissionsEndpointTest.java @@ -0,0 +1,39 @@ +package com.gentics.mesh.core.node; + +import static com.gentics.mesh.test.TestDataProvider.PROJECT_NAME; +import static com.gentics.mesh.test.TestSize.PROJECT_AND_NODE; + +import com.gentics.mesh.core.data.HibBaseElement; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; +import com.gentics.mesh.test.MeshTestSetting; +import com.gentics.mesh.test.context.AbstractRolePermissionEndpointTest; +import com.gentics.mesh.test.context.ClientHandler; + +/** + * Test cases for handling role permissions for nodes + */ +@MeshTestSetting(testSize = PROJECT_AND_NODE, startServer = true) +public class NodeRolePermissionsEndpointTest extends AbstractRolePermissionEndpointTest { + + @Override + protected HibBaseElement getTestedElement() { + return folder("2015"); + } + + @Override + protected ClientHandler getRolePermissions() { + return () -> client().getNodeRolePermissions(PROJECT_NAME, getTestedUuid()); + } + + @Override + protected ClientHandler grantRolePermissions(ObjectPermissionGrantRequest request) { + return () -> client().grantNodeRolePermissions(PROJECT_NAME, getTestedUuid(), request); + } + + @Override + protected ClientHandler revokeRolePermissions(ObjectPermissionRevokeRequest request) { + return () -> client().revokeNodeRolePermissions(PROJECT_NAME, getTestedUuid(), request); + } +} diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/project/ProjectRolePermissionsEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/project/ProjectRolePermissionsEndpointTest.java new file mode 100644 index 0000000000..6458fe2da2 --- /dev/null +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/project/ProjectRolePermissionsEndpointTest.java @@ -0,0 +1,38 @@ +package com.gentics.mesh.core.project; + +import static com.gentics.mesh.test.TestSize.PROJECT_AND_NODE; + +import com.gentics.mesh.core.data.HibBaseElement; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; +import com.gentics.mesh.test.MeshTestSetting; +import com.gentics.mesh.test.context.AbstractRolePermissionEndpointTest; +import com.gentics.mesh.test.context.ClientHandler; + +/** + * Test cases for handling role permissions for projects + */ +@MeshTestSetting(testSize = PROJECT_AND_NODE, startServer = true) +public class ProjectRolePermissionsEndpointTest extends AbstractRolePermissionEndpointTest { + + @Override + protected HibBaseElement getTestedElement() { + return project(); + } + + @Override + protected ClientHandler getRolePermissions() { + return () -> client().getProjectRolePermissions(getTestedUuid()); + } + + @Override + protected ClientHandler grantRolePermissions(ObjectPermissionGrantRequest request) { + return () -> client().grantProjectRolePermissions(getTestedUuid(), request); + } + + @Override + protected ClientHandler revokeRolePermissions(ObjectPermissionRevokeRequest request) { + return () -> client().revokeProjectRolePermissions(getTestedUuid(), request); + } +} diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/role/RoleRolePermissionsEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/role/RoleRolePermissionsEndpointTest.java new file mode 100644 index 0000000000..18988fa29c --- /dev/null +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/role/RoleRolePermissionsEndpointTest.java @@ -0,0 +1,38 @@ +package com.gentics.mesh.core.role; + +import static com.gentics.mesh.test.TestSize.PROJECT_AND_NODE; + +import com.gentics.mesh.core.data.HibBaseElement; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; +import com.gentics.mesh.test.MeshTestSetting; +import com.gentics.mesh.test.context.AbstractRolePermissionEndpointTest; +import com.gentics.mesh.test.context.ClientHandler; + +/** + * Test cases for handling role permissions for roles + */ +@MeshTestSetting(testSize = PROJECT_AND_NODE, startServer = true) +public class RoleRolePermissionsEndpointTest extends AbstractRolePermissionEndpointTest { + + @Override + protected HibBaseElement getTestedElement() { + return roles().get("anonymous"); + } + + @Override + protected ClientHandler getRolePermissions() { + return () -> client().getRoleRolePermissions(getTestedUuid()); + } + + @Override + protected ClientHandler grantRolePermissions(ObjectPermissionGrantRequest request) { + return () -> client().grantRoleRolePermissions(getTestedUuid(), request); + } + + @Override + protected ClientHandler revokeRolePermissions(ObjectPermissionRevokeRequest request) { + return () -> client().revokeRoleRolePermissions(getTestedUuid(), request); + } +} diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/role/RoleTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/role/RoleTest.java index ffd93ada1f..9d29c30151 100644 --- a/tests/tests-core/src/main/java/com/gentics/mesh/core/role/RoleTest.java +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/role/RoleTest.java @@ -2,15 +2,22 @@ import static com.gentics.mesh.core.data.perm.InternalPermission.CREATE_PERM; import static com.gentics.mesh.core.data.perm.InternalPermission.DELETE_PERM; +import static com.gentics.mesh.core.data.perm.InternalPermission.PUBLISH_PERM; import static com.gentics.mesh.core.data.perm.InternalPermission.READ_PERM; +import static com.gentics.mesh.core.data.perm.InternalPermission.READ_PUBLISHED_PERM; import static com.gentics.mesh.core.data.perm.InternalPermission.UPDATE_PERM; import static com.gentics.mesh.test.TestSize.PROJECT; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; import java.util.Set; import org.junit.Test; @@ -127,6 +134,137 @@ public void testGrantPermissionTwice() { } } + @Test + public void testGrantMultiplePermission() { + // change permissions on multiple roles + try (Tx tx = tx()) { + RoleDao roleDao = tx.roleDao(); + HibRole admin = roleDao.findByName("admin"); + assertThat(admin).as("Admin role").isNotNull(); + HibRole anonymous = roleDao.findByName("anonymous"); + assertThat(anonymous).as("Anonymous role").isNotNull(); + HibRole testRole = role(); + assertThat(testRole).as("Test role").isNotNull(); + HibNode node = folder("news"); + + assertThat(roleDao.grantPermissions(new HashSet<>(Arrays.asList(admin, anonymous)), node, false, + CREATE_PERM, READ_PERM)).as("Changed permissions").isTrue(); + + assertThat(roleDao.getPermissions(admin, node)).as("Permissions for admin").containsOnly(CREATE_PERM, + READ_PERM); + assertThat(roleDao.getPermissions(anonymous, node)).as("Permissions for anonymous") + .containsOnly(CREATE_PERM, READ_PERM); + assertThat(roleDao.getPermissions(testRole, node)).as("Permissions for test role").containsOnly(CREATE_PERM, + PUBLISH_PERM, UPDATE_PERM, READ_PERM, DELETE_PERM, READ_PUBLISHED_PERM); + tx.success(); + } + + // change permissions and check the unmentioned roles are not touched + try (Tx tx = tx()) { + RoleDao roleDao = tx.roleDao(); + HibRole admin = roleDao.findByName("admin"); + assertThat(admin).as("Admin role").isNotNull(); + HibRole anonymous = roleDao.findByName("anonymous"); + assertThat(anonymous).as("Anonymous role").isNotNull(); + HibRole testRole = role(); + assertThat(testRole).as("Test role").isNotNull(); + HibNode node = folder("news"); + + assertThat(roleDao.grantPermissions(new HashSet<>(Arrays.asList(admin, testRole)), node, false, + UPDATE_PERM)).as("Changed permissions").isTrue(); + + assertThat(roleDao.getPermissions(admin, node)).as("Permissions for admin").containsOnly(CREATE_PERM, + READ_PERM, UPDATE_PERM); + assertThat(roleDao.getPermissions(anonymous, node)).as("Permissions for anonymous") + .containsOnly(CREATE_PERM, READ_PERM); + assertThat(roleDao.getPermissions(testRole, node)).as("Permissions for test role").containsOnly(CREATE_PERM, + PUBLISH_PERM, UPDATE_PERM, READ_PERM, DELETE_PERM, READ_PUBLISHED_PERM); + tx.success(); + } + + // "change" something that is already set + try (Tx tx = tx()) { + RoleDao roleDao = tx.roleDao(); + HibRole admin = roleDao.findByName("admin"); + assertThat(admin).as("Admin role").isNotNull(); + HibRole anonymous = roleDao.findByName("anonymous"); + assertThat(anonymous).as("Anonymous role").isNotNull(); + HibRole testRole = role(); + assertThat(testRole).as("Test role").isNotNull(); + HibNode node = folder("news"); + + assertThat(roleDao.grantPermissions(new HashSet<>(Arrays.asList(admin, anonymous, testRole)), node, false, + CREATE_PERM, READ_PERM)).as("Changed permissions").isFalse(); + tx.success(); + } + } + + @Test + public void testGrantMultiplePermissionExclusive() { + // change permissions on multiple roles + try (Tx tx = tx()) { + RoleDao roleDao = tx.roleDao(); + HibRole admin = roleDao.findByName("admin"); + assertThat(admin).as("Admin role").isNotNull(); + HibRole anonymous = roleDao.findByName("anonymous"); + assertThat(anonymous).as("Anonymous role").isNotNull(); + HibRole testRole = role(); + assertThat(testRole).as("Test role").isNotNull(); + HibNode node = folder("news"); + + assertThat(roleDao.grantPermissions(new HashSet<>(Arrays.asList(admin, anonymous)), node, true, + CREATE_PERM, READ_PERM)).as("Changed permissions").isTrue(); + + assertThat(roleDao.getPermissions(admin, node)).as("Permissions for admin").containsOnly(CREATE_PERM, + READ_PERM); + assertThat(roleDao.getPermissions(anonymous, node)).as("Permissions for anonymous") + .containsOnly(CREATE_PERM, READ_PERM); + assertThat(roleDao.getPermissions(testRole, node)).as("Permissions for test role") + .containsOnly(PUBLISH_PERM, UPDATE_PERM, DELETE_PERM, READ_PUBLISHED_PERM); + tx.success(); + } + + // "change" something that is already set + try (Tx tx = tx()) { + RoleDao roleDao = tx.roleDao(); + HibRole admin = roleDao.findByName("admin"); + assertThat(admin).as("Admin role").isNotNull(); + HibRole anonymous = roleDao.findByName("anonymous"); + assertThat(anonymous).as("Anonymous role").isNotNull(); + HibRole testRole = role(); + assertThat(testRole).as("Test role").isNotNull(); + HibNode node = folder("news"); + + assertThat(roleDao.grantPermissions(new HashSet<>(Arrays.asList(admin, anonymous)), node, true, READ_PERM)) + .as("Changed permissions").isFalse(); + tx.success(); + } + + // do a change, that only restricts other roles further + try (Tx tx = tx()) { + RoleDao roleDao = tx.roleDao(); + HibRole admin = roleDao.findByName("admin"); + assertThat(admin).as("Admin role").isNotNull(); + HibRole anonymous = roleDao.findByName("anonymous"); + assertThat(anonymous).as("Anonymous role").isNotNull(); + HibRole testRole = role(); + assertThat(testRole).as("Test role").isNotNull(); + HibNode node = folder("news"); + + assertThat(roleDao.grantPermissions(new HashSet<>(Arrays.asList(admin)), node, true, READ_PERM)) + .as("Changed permissions").isTrue(); + + assertThat(roleDao.getPermissions(admin, node)).as("Permissions for admin").containsOnly(CREATE_PERM, + READ_PERM); + assertThat(roleDao.getPermissions(anonymous, node)).as("Permissions for anonymous") + .containsOnly(CREATE_PERM); + assertThat(roleDao.getPermissions(testRole, node)).as("Permissions for test role") + .containsOnly(PUBLISH_PERM, UPDATE_PERM, DELETE_PERM, READ_PUBLISHED_PERM); + tx.success(); + } + + } + @Test public void testGetPermissions() { try (Tx tx = tx()) { @@ -137,6 +275,37 @@ public void testGetPermissions() { } } + @Test + public void testGetMultiplePermissions() { + try (Tx tx = tx()) { + RoleDao roleDao = tx.roleDao(); + HibRole admin = roleDao.findByName("admin"); + assertThat(admin).as("Admin role").isNotNull(); + HibRole anonymous = roleDao.findByName("anonymous"); + assertThat(anonymous).as("Anonymous role").isNotNull(); + HibRole testRole = role(); + assertThat(testRole).as("Test role").isNotNull(); + HibNode node = folder("news"); + Map> result = roleDao.getPermissions(new HashSet<>(Arrays.asList(admin, anonymous, testRole)), node); + assertThat(result).as("Permissions result") + .containsOnlyKeys(admin, anonymous, testRole) + .containsEntry(testRole, new HashSet<>(Arrays.asList(CREATE_PERM, PUBLISH_PERM, UPDATE_PERM, READ_PERM, DELETE_PERM, READ_PUBLISHED_PERM))) + .containsEntry(admin, Collections.emptySet()) + .containsEntry(anonymous, Collections.emptySet()); + } + } + + @Test + public void testGetMultiplePermissionsForNoRoles() { + try (Tx tx = tx()) { + RoleDao roleDao = tx.roleDao(); + HibNode node = folder("news"); + Map> result = roleDao.getPermissions(Collections.emptySet(), node); + assertThat(result).as("Permissions result") + .isEmpty(); + } + } + @Test public void testRevokePermission() { try (Tx tx = tx()) { @@ -154,6 +323,52 @@ public void testRevokePermission() { } } + @Test + public void testRevokeMultiplePermissions() { + // revoke permissions + try (Tx tx = tx()) { + RoleDao roleDao = tx.roleDao(); + HibRole admin = roleDao.findByName("admin"); + assertThat(admin).as("Admin role").isNotNull(); + HibRole anonymous = roleDao.findByName("anonymous"); + assertThat(anonymous).as("Anonymous role").isNotNull(); + HibRole testRole = role(); + assertThat(testRole).as("Test role").isNotNull(); + HibNode node = folder("news"); + + roleDao.grantPermissions(admin, node, CREATE_PERM, UPDATE_PERM); + roleDao.grantPermissions(anonymous, node, CREATE_PERM); + + assertThat(roleDao.revokePermissions(new HashSet<>(Arrays.asList(admin, testRole)), node, CREATE_PERM, + READ_PERM)).as("Permissions were changed").isTrue(); + + assertThat(roleDao.getPermissions(admin, node)).as("Permissions for admin").containsOnly(UPDATE_PERM); + assertThat(roleDao.getPermissions(anonymous, node)).as("Permissions for anonymous") + .containsOnly(CREATE_PERM); + assertThat(roleDao.getPermissions(testRole, node)).as("Permissions for test role") + .containsOnly(PUBLISH_PERM, UPDATE_PERM, DELETE_PERM, READ_PUBLISHED_PERM); + + tx.success(); + } + + // try again (nothing is changed) + try (Tx tx = tx()) { + RoleDao roleDao = tx.roleDao(); + HibRole admin = roleDao.findByName("admin"); + assertThat(admin).as("Admin role").isNotNull(); + HibRole anonymous = roleDao.findByName("anonymous"); + assertThat(anonymous).as("Anonymous role").isNotNull(); + HibRole testRole = role(); + assertThat(testRole).as("Test role").isNotNull(); + HibNode node = folder("news"); + + assertThat(roleDao.revokePermissions(new HashSet<>(Arrays.asList(admin, testRole)), node, CREATE_PERM, + READ_PERM)).as("Permissions were changed").isFalse(); + + tx.success(); + } + } + @Test public void testRevokePermissionOnGroupRoot() throws Exception { try (Tx tx = tx()) { diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/MicroschemaRolePermissionsEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/MicroschemaRolePermissionsEndpointTest.java new file mode 100644 index 0000000000..b37429f7b1 --- /dev/null +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/MicroschemaRolePermissionsEndpointTest.java @@ -0,0 +1,38 @@ +package com.gentics.mesh.core.schema; + +import static com.gentics.mesh.test.TestSize.FULL; + +import com.gentics.mesh.core.data.HibBaseElement; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; +import com.gentics.mesh.test.MeshTestSetting; +import com.gentics.mesh.test.context.AbstractRolePermissionEndpointTest; +import com.gentics.mesh.test.context.ClientHandler; + +/** + * Test cases for handling role permissions for microschemas + */ +@MeshTestSetting(testSize = FULL, startServer = true) +public class MicroschemaRolePermissionsEndpointTest extends AbstractRolePermissionEndpointTest { + + @Override + protected HibBaseElement getTestedElement() { + return microschemaContainer("vcard"); + } + + @Override + protected ClientHandler getRolePermissions() { + return () -> client().getMicroschemaRolePermissions(getTestedUuid()); + } + + @Override + protected ClientHandler grantRolePermissions(ObjectPermissionGrantRequest request) { + return () -> client().grantMicroschemaRolePermissions(getTestedUuid(), request); + } + + @Override + protected ClientHandler revokeRolePermissions(ObjectPermissionRevokeRequest request) { + return () -> client().revokeMicroschemaRolePermissions(getTestedUuid(), request); + } +} diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/SchemaRolePermissionsEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/SchemaRolePermissionsEndpointTest.java new file mode 100644 index 0000000000..76f793349f --- /dev/null +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/SchemaRolePermissionsEndpointTest.java @@ -0,0 +1,38 @@ +package com.gentics.mesh.core.schema; + +import static com.gentics.mesh.test.TestSize.FULL; + +import com.gentics.mesh.core.data.HibBaseElement; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; +import com.gentics.mesh.test.MeshTestSetting; +import com.gentics.mesh.test.context.AbstractRolePermissionEndpointTest; +import com.gentics.mesh.test.context.ClientHandler; + +/** + * Test cases for handling role permissions for schemas + */ +@MeshTestSetting(testSize = FULL, startServer = true) +public class SchemaRolePermissionsEndpointTest extends AbstractRolePermissionEndpointTest { + + @Override + protected HibBaseElement getTestedElement() { + return schemaContainer("content"); + } + + @Override + protected ClientHandler getRolePermissions() { + return () -> client().getSchemaRolePermissions(getTestedUuid()); + } + + @Override + protected ClientHandler grantRolePermissions(ObjectPermissionGrantRequest request) { + return () -> client().grantSchemaRolePermissions(getTestedUuid(), request); + } + + @Override + protected ClientHandler revokeRolePermissions(ObjectPermissionRevokeRequest request) { + return () -> client().revokeRoleRolePermissions(getTestedUuid(), request); + } +} diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/tag/TagRolePermissionsEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/tag/TagRolePermissionsEndpointTest.java new file mode 100644 index 0000000000..5fa943dea9 --- /dev/null +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/tag/TagRolePermissionsEndpointTest.java @@ -0,0 +1,45 @@ +package com.gentics.mesh.core.tag; + +import static com.gentics.mesh.test.TestDataProvider.PROJECT_NAME; +import static com.gentics.mesh.test.TestSize.FULL; + +import com.gentics.mesh.core.data.HibBaseElement; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; +import com.gentics.mesh.test.MeshTestSetting; +import com.gentics.mesh.test.context.AbstractRolePermissionEndpointTest; +import com.gentics.mesh.test.context.ClientHandler; + +/** + * Test cases for handling role permissions for tags + */ +@MeshTestSetting(testSize = FULL, startServer = true) +public class TagRolePermissionsEndpointTest extends AbstractRolePermissionEndpointTest { + + @Override + protected HibBaseElement getTestedElement() { + return tag("red"); + } + + @Override + protected ClientHandler getRolePermissions() { + String tagFamilyUuid = tx(() -> tagFamily("colors").getUuid()); + String uuid = getTestedUuid(); + return () -> client().getTagRolePermissions(PROJECT_NAME, tagFamilyUuid, uuid); + } + + @Override + protected ClientHandler grantRolePermissions(ObjectPermissionGrantRequest request) { + String tagFamilyUuid = tx(() -> tagFamily("colors").getUuid()); + String uuid = getTestedUuid(); + return () -> client().grantTagRolePermissions(PROJECT_NAME, tagFamilyUuid, uuid, request); + } + + @Override + protected ClientHandler revokeRolePermissions(ObjectPermissionRevokeRequest request) { + String tagFamilyUuid = tx(() -> tagFamily("colors").getUuid()); + String uuid = getTestedUuid(); + return () -> client().revokeTagRolePermissions(PROJECT_NAME, tagFamilyUuid, uuid, request); + } +} diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/tagfamily/TagFamilyRolePermissionsEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/tagfamily/TagFamilyRolePermissionsEndpointTest.java new file mode 100644 index 0000000000..1475b88912 --- /dev/null +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/tagfamily/TagFamilyRolePermissionsEndpointTest.java @@ -0,0 +1,39 @@ +package com.gentics.mesh.core.tagfamily; + +import static com.gentics.mesh.test.TestDataProvider.PROJECT_NAME; +import static com.gentics.mesh.test.TestSize.FULL; + +import com.gentics.mesh.core.data.HibBaseElement; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; +import com.gentics.mesh.test.MeshTestSetting; +import com.gentics.mesh.test.context.AbstractRolePermissionEndpointTest; +import com.gentics.mesh.test.context.ClientHandler; + +/** + * Test cases for handling role permissions for tag families + */ +@MeshTestSetting(testSize = FULL, startServer = true) +public class TagFamilyRolePermissionsEndpointTest extends AbstractRolePermissionEndpointTest { + + @Override + protected HibBaseElement getTestedElement() { + return tagFamily("colors"); + } + + @Override + protected ClientHandler getRolePermissions() { + return () -> client().getTagFamilyRolePermissions(PROJECT_NAME, getTestedUuid()); + } + + @Override + protected ClientHandler grantRolePermissions(ObjectPermissionGrantRequest request) { + return () -> client().grantTagFamilyRolePermissions(PROJECT_NAME, getTestedUuid(), request); + } + + @Override + protected ClientHandler revokeRolePermissions(ObjectPermissionRevokeRequest request) { + return () -> client().revokeTagFamilyRolePermissions(PROJECT_NAME, getTestedUuid(), request); + } +} diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/user/UserRolePermissionsEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/user/UserRolePermissionsEndpointTest.java new file mode 100644 index 0000000000..6740c79847 --- /dev/null +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/user/UserRolePermissionsEndpointTest.java @@ -0,0 +1,38 @@ +package com.gentics.mesh.core.user; + +import static com.gentics.mesh.test.TestSize.PROJECT_AND_NODE; + +import com.gentics.mesh.core.data.HibBaseElement; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; +import com.gentics.mesh.test.MeshTestSetting; +import com.gentics.mesh.test.context.AbstractRolePermissionEndpointTest; +import com.gentics.mesh.test.context.ClientHandler; + +/** + * Test cases for handling role permissions for users + */ +@MeshTestSetting(testSize = PROJECT_AND_NODE, startServer = true) +public class UserRolePermissionsEndpointTest extends AbstractRolePermissionEndpointTest { + + @Override + protected HibBaseElement getTestedElement() { + return user(); + } + + @Override + protected ClientHandler getRolePermissions() { + return () -> client().getUserRolePermissions(getTestedUuid()); + } + + @Override + protected ClientHandler grantRolePermissions(ObjectPermissionGrantRequest request) { + return () -> client().grantUserRolePermissions(getTestedUuid(), request); + } + + @Override + protected ClientHandler revokeRolePermissions(ObjectPermissionRevokeRequest request) { + return () -> client().revokeUserRolePermissions(getTestedUuid(), request); + } +} diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/test/context/AbstractRolePermissionEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/test/context/AbstractRolePermissionEndpointTest.java new file mode 100644 index 0000000000..b323dd5906 --- /dev/null +++ b/tests/tests-core/src/main/java/com/gentics/mesh/test/context/AbstractRolePermissionEndpointTest.java @@ -0,0 +1,424 @@ +package com.gentics.mesh.test.context; + +import static com.gentics.mesh.core.data.perm.InternalPermission.CREATE_PERM; +import static com.gentics.mesh.core.data.perm.InternalPermission.READ_PERM; +import static com.gentics.mesh.core.data.perm.InternalPermission.UPDATE_PERM; +import static com.gentics.mesh.test.ClientHelper.call; +import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; +import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; +import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Set; + +import org.junit.Test; + +import com.gentics.mesh.core.data.HibBaseElement; +import com.gentics.mesh.core.data.perm.InternalPermission; +import com.gentics.mesh.core.data.role.HibRole; +import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; +import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; +import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; +import com.gentics.mesh.core.rest.role.RoleReference; +import com.gentics.mesh.util.UUIDUtil; + +/** + * Abstract test class for role permissions test + */ +public abstract class AbstractRolePermissionEndpointTest extends AbstractMeshTest { + /** + * Test reading role permissions + */ + @Test + public void testReadRolePermissions() { + boolean hasPublishPermissions = tx(() -> getTestedElement().hasPublishPermissions()); + RoleReference testRole = tx(() -> role().transformToReference()); + + ObjectPermissionResponse response = call(getRolePermissions()); + assertThat(response).as("Response").isNotNull(); + assertThat(response.getCreate()).as("Roles with create permission").containsOnly(testRole); + assertThat(response.getDelete()).as("Roles with delete permission").containsOnly(testRole); + assertThat(response.getRead()).as("Roles with read permission").containsOnly(testRole); + assertThat(response.getUpdate()).as("Roles with update permission").containsOnly(testRole); + if (hasPublishPermissions) { + assertThat(response.getPublish()).as("Roles with publish permission").containsOnly(testRole); + assertThat(response.getReadPublished()).as("Roles with readPublished permission").containsOnly(testRole); + } else { + assertThat(response.getPublish()).as("Roles with publish permission").isNull(); + assertThat(response.getReadPublished()).as("Roles with readPublished permission").isNull(); + } + } + + /** + * Test reading role permissions without permission on the object itself + */ + @Test + public void testReadRolePermissionWithoutPermission() { + revokeReadOnTestedElement(); + String uuid = getTestedUuid(); + call(getRolePermissions(), FORBIDDEN, "error_missing_perm", uuid, READ_PERM.getRestPerm().getName()); + } + + /** + * Test reading role permissions without permission on all roles + */ + @Test + public void testReadRolePermissionWithoutPermissionOnRole() { + boolean hasPublishPermissions = tx(() -> getTestedElement().hasPublishPermissions()); + revokeReadOnRole(); + + ObjectPermissionResponse response = call(getRolePermissions()); + assertThat(response).as("Response").isNotNull(); + assertThat(response.getCreate()).as("Roles with create permission").isNotNull().isEmpty(); + assertThat(response.getDelete()).as("Roles with delete permission").isNotNull().isEmpty(); + assertThat(response.getRead()).as("Roles with read permission").isNotNull().isEmpty(); + assertThat(response.getUpdate()).as("Roles with update permission").isNotNull().isEmpty(); + if (hasPublishPermissions) { + assertThat(response.getPublish()).as("Roles with publish permission").isNotNull().isEmpty();; + assertThat(response.getReadPublished()).as("Roles with readPublished permission").isNotNull().isEmpty(); + } else { + assertThat(response.getPublish()).as("Roles with publish permission").isNull(); + assertThat(response.getReadPublished()).as("Roles with readPublished permission").isNull(); + } + } + + /** + * Test granting role permissions by uuid + */ + @Test + public void testGrantRolePermissionsByUuid() { + String anonymousUuid = tx(() -> roles().get("anonymous").getUuid()); + RoleReference anonymous = tx(() -> roles().get("anonymous").transformToReference()); + RoleReference testRole = tx(() -> role().transformToReference()); + + ObjectPermissionGrantRequest request = new ObjectPermissionGrantRequest(); + request.setRead(Arrays.asList(new RoleReference().setUuid(anonymousUuid))); + ObjectPermissionResponse response = call(grantRolePermissions(request)); + assertThat(response).as("Response").isNotNull(); + assertThat(response.getRead()).as("Roles with read permission").isNotNull().containsOnly(anonymous, testRole); + assertThat(response.getCreate()).as("Roles with create permission").isNotNull().containsOnly(testRole); + } + + /** + * Test granting role permissions by name + */ + @Test + public void testGrantRolePermissionsByName() { + RoleReference anonymous = tx(() -> roles().get("anonymous").transformToReference()); + RoleReference testRole = tx(() -> role().transformToReference()); + + ObjectPermissionGrantRequest request = new ObjectPermissionGrantRequest(); + request.setUpdate(Arrays.asList(new RoleReference().setName("anonymous"))); + ObjectPermissionResponse response = call(grantRolePermissions(request)); + assertThat(response).as("Response").isNotNull(); + assertThat(response.getUpdate()).as("Roles with update permission").isNotNull().containsOnly(anonymous, testRole); + assertThat(response.getDelete()).as("Roles with delete permission").isNotNull().containsOnly(testRole); + } + + /** + * Test granting role permissions by unknown uuid + */ + @Test + public void testGrantUnknownRolePermissionsByUuid() { + String randomUUID = UUIDUtil.randomUUID(); + ObjectPermissionGrantRequest request = new ObjectPermissionGrantRequest(); + request.setUpdate(Arrays.asList(new RoleReference().setUuid(randomUUID))); + call(grantRolePermissions(request), NOT_FOUND, "object_not_found_for_uuid", randomUUID); + } + + /** + * Test granting role permissions by unknown name + */ + @Test + public void testGrantUnknownRolePermissionsByName() { + ObjectPermissionGrantRequest request = new ObjectPermissionGrantRequest(); + request.setDelete(Arrays.asList(new RoleReference().setName("bogus"))); + call(grantRolePermissions(request), NOT_FOUND, "object_not_found_for_name", "bogus"); + } + + /** + * Test granting role permissions by neither uuid nor name + */ + @Test + public void testGrantInvalidRolePermissions() { + ObjectPermissionGrantRequest request = new ObjectPermissionGrantRequest(); + request.setCreate(Arrays.asList(new RoleReference())); + call(grantRolePermissions(request), BAD_REQUEST, "role_reference_uuid_or_name_missing"); + } + + /** + * Test granting roles permissions exclusively + */ + @Test + public void testGrantRolePermissionsExclusive() { + String anonymousUuid = tx(() -> roles().get("anonymous").getUuid()); + RoleReference anonymous = tx(() -> roles().get("anonymous").transformToReference()); + RoleReference testRole = tx(() -> role().transformToReference()); + + tx(tx -> { + HibRole adminObj = roles().get("admin"); + HibRole testRoleObj = role(); + + // revoke the permission on the admin role + tx.roleDao().revokePermissions(testRoleObj, adminObj, READ_PERM); + + // grant some permissions to the admin role + tx.roleDao().grantPermissions(adminObj, getTestedElement(), UPDATE_PERM, CREATE_PERM, READ_PERM); + }); + + ObjectPermissionGrantRequest request = new ObjectPermissionGrantRequest(); + request.setCreate(Arrays.asList(new RoleReference().setUuid(anonymousUuid))); + request.setDelete(Arrays.asList(new RoleReference().setUuid(anonymousUuid))); + request.setExclusive(true); + ObjectPermissionResponse response = call(grantRolePermissions(request)); + assertThat(response).as("Response").isNotNull(); + assertThat(response.getRead()).as("Roles with read permission").isNotNull().containsOnly(testRole); + assertThat(response.getUpdate()).as("Roles with update permission").isNotNull().containsOnly(testRole); + assertThat(response.getCreate()).as("Roles with create permission").isNotNull().containsOnly(anonymous); + assertThat(response.getDelete()).as("Roles with delete permission").isNotNull().containsOnly(anonymous); + + // check that admin permissions were not changed + Set adminPermissions = tx(tx -> { + return tx.roleDao().getPermissions(roles().get("admin"), getTestedElement()); + }); + assertThat(adminPermissions).as("Permissions for role admin").isNotNull().containsOnly(UPDATE_PERM, CREATE_PERM, READ_PERM); + } + + /** + * Test granting roles permissions exclusively while ignoring roles + */ + @Test + public void testGrantRolePermissionsExclusiveWithIgnore() { + String anonymousUuid = tx(() -> roles().get("anonymous").getUuid()); + RoleReference anonymous = tx(() -> roles().get("anonymous").transformToReference()); + RoleReference testRole = tx(() -> role().transformToReference()); + + tx(tx -> { + HibRole adminObj = roles().get("admin"); + HibRole testRoleObj = role(); + + // revoke the permission on the admin role + tx.roleDao().revokePermissions(testRoleObj, adminObj, READ_PERM); + + // grant some permissions to the admin role + tx.roleDao().grantPermissions(adminObj, getTestedElement(), UPDATE_PERM, CREATE_PERM, READ_PERM); + }); + + ObjectPermissionGrantRequest request = new ObjectPermissionGrantRequest(); + request.setCreate(Arrays.asList(new RoleReference().setUuid(anonymousUuid))); + request.setDelete(Arrays.asList(new RoleReference().setUuid(anonymousUuid))); + request.setExclusive(true); + request.setIgnore(Arrays.asList(testRole)); + ObjectPermissionResponse response = call(grantRolePermissions(request)); + assertThat(response).as("Response").isNotNull(); + assertThat(response.getRead()).as("Roles with read permission").isNotNull().containsOnly(testRole); + assertThat(response.getUpdate()).as("Roles with update permission").isNotNull().containsOnly(testRole); + assertThat(response.getCreate()).as("Roles with create permission").isNotNull().containsOnly(anonymous, testRole); + assertThat(response.getDelete()).as("Roles with delete permission").isNotNull().containsOnly(anonymous, testRole); + + // check that admin permissions were not changed + Set adminPermissions = tx(tx -> { + return tx.roleDao().getPermissions(roles().get("admin"), getTestedElement()); + }); + assertThat(adminPermissions).as("Permissions for role admin").isNotNull().containsOnly(UPDATE_PERM, CREATE_PERM, READ_PERM); + } + + /** + * Test granting role without permission on the entity + */ + @Test + public void testGrantRoleWithoutPermission() { + String uuid = getTestedUuid(); + revokeReadOnTestedElement(); + ObjectPermissionGrantRequest request = new ObjectPermissionGrantRequest(); + call(grantRolePermissions(request), FORBIDDEN, "error_missing_perm", uuid, READ_PERM.getRestPerm().getName()); + } + + /** + * Test granting role without read permission on the role + */ + @Test + public void testGrantRoleWithoutReadPermissionOnRole() { + String testRoleUuid = tx(() -> role().getUuid()); + RoleReference testRoleRef = tx(() -> role().transformToReference()); + revokeReadOnRole(); + ObjectPermissionGrantRequest request = new ObjectPermissionGrantRequest(); + request.setCreate(Arrays.asList(testRoleRef)); + call(grantRolePermissions(request), NOT_FOUND, "object_not_found_for_uuid", testRoleUuid); + } + + /** + * Test granting role without update permission on the role + */ + @Test + public void testGrantRoleWithoutUpdatePermissionOnRole() { + String testRoleUuid = tx(() -> role().getUuid()); + RoleReference testRoleRef = tx(() -> role().transformToReference()); + revokeUpdateOnRole(); + ObjectPermissionGrantRequest request = new ObjectPermissionGrantRequest(); + request.setCreate(Arrays.asList(testRoleRef)); + call(grantRolePermissions(request), FORBIDDEN, "error_missing_perm", testRoleUuid, UPDATE_PERM.getRestPerm().getName()); + } + + /** + * Test revoking permissions by uuid + */ + @Test + public void testRevokeRolePermissionsByUuid() { + String testRoleUuid = tx(() -> role().getUuid()); + RoleReference testRole = tx(() -> role().transformToReference()); + + ObjectPermissionRevokeRequest request = new ObjectPermissionRevokeRequest(); + request.setCreate(Arrays.asList(new RoleReference().setUuid(testRoleUuid))); + ObjectPermissionResponse response = call(revokeRolePermissions(request)); + assertThat(response).as("Response").isNotNull(); + assertThat(response.getCreate()).as("Roles with create permission").isNotNull().isEmpty(); + assertThat(response.getRead()).as("Roles with read permission").isNotNull().containsOnly(testRole); + } + + /** + * Test revoking role permissions by name + */ + @Test + public void testRevokeRolePermissionsByName() { + String testRoleName = tx(() -> role().getName()); + RoleReference testRole = tx(() -> role().transformToReference()); + + ObjectPermissionRevokeRequest request = new ObjectPermissionRevokeRequest(); + request.setUpdate(Arrays.asList(new RoleReference().setName(testRoleName))); + ObjectPermissionResponse response = call(revokeRolePermissions(request)); + assertThat(response).as("Response").isNotNull(); + assertThat(response.getUpdate()).as("Roles with update permission").isNotNull().isEmpty(); + assertThat(response.getDelete()).as("Roles with delete permission").isNotNull().containsOnly(testRole); + } + + /** + * Test revoking role permissions by unknown uuid + */ + @Test + public void testRevokeUnknownRolePermissionsByUuid() { + String randomUUID = UUIDUtil.randomUUID(); + ObjectPermissionRevokeRequest request = new ObjectPermissionRevokeRequest(); + request.setUpdate(Arrays.asList(new RoleReference().setUuid(randomUUID))); + call(revokeRolePermissions(request), NOT_FOUND, "object_not_found_for_uuid", randomUUID); + } + + /** + * Test revoking role permissions by unknown name + */ + @Test + public void testRevoketUnknownRolePermissionsByName() { + ObjectPermissionRevokeRequest request = new ObjectPermissionRevokeRequest(); + request.setDelete(Arrays.asList(new RoleReference().setName("bogus"))); + call(revokeRolePermissions(request), NOT_FOUND, "object_not_found_for_name", "bogus"); + } + + /** + * Test revoking role permissions by neither uuid nor name + */ + @Test + public void testRevokeInvalidRolePermissions() { + ObjectPermissionRevokeRequest request = new ObjectPermissionRevokeRequest(); + request.setCreate(Arrays.asList(new RoleReference())); + call(revokeRolePermissions(request), BAD_REQUEST, "role_reference_uuid_or_name_missing"); + } + + /** + * Test revoking role without permission on the entity + */ + @Test + public void testRevokeRoleWithoutPermission() { + String uuid = getTestedUuid(); + revokeReadOnTestedElement(); + ObjectPermissionRevokeRequest request = new ObjectPermissionRevokeRequest(); + call(revokeRolePermissions(request), FORBIDDEN, "error_missing_perm", uuid, READ_PERM.getRestPerm().getName()); + } + + /** + * Test revoking role without read permission on the role + */ + @Test + public void testRevokeRoleWithoutReadPermissionOnRole() { + String testRoleUuid = tx(() -> role().getUuid()); + RoleReference testRoleRef = tx(() -> role().transformToReference()); + revokeReadOnRole(); + ObjectPermissionRevokeRequest request = new ObjectPermissionRevokeRequest(); + request.setCreate(Arrays.asList(testRoleRef)); + call(revokeRolePermissions(request), NOT_FOUND, "object_not_found_for_uuid", testRoleUuid); + } + + /** + * Test revoking role without update permission on the role + */ + @Test + public void testRevokeRoleWithoutUpdatePermissionOnRole() { + String testRoleUuid = tx(() -> role().getUuid()); + RoleReference testRoleRef = tx(() -> role().transformToReference()); + revokeUpdateOnRole(); + ObjectPermissionRevokeRequest request = new ObjectPermissionRevokeRequest(); + request.setCreate(Arrays.asList(testRoleRef)); + call(revokeRolePermissions(request), FORBIDDEN, "error_missing_perm", testRoleUuid, UPDATE_PERM.getRestPerm().getName()); + } + + /** + * Get the tested element (this method assumes a running transaction) + * @return tested element + */ + protected abstract HibBaseElement getTestedElement(); + + /** + * Get the uuid of the tested element + * @return uuid + */ + protected String getTestedUuid() { + return tx(() -> getTestedElement().getUuid()); + } + + /** + * Revoke the read permission on the tested element + */ + protected void revokeReadOnTestedElement() { + tx(tx -> { + tx.roleDao().revokePermissions(role(), getTestedElement(), READ_PERM); + }); + } + + /** + * Revoke the read permission on the role + */ + protected void revokeReadOnRole() { + tx(tx -> { + tx.roleDao().revokePermissions(role(), role(), READ_PERM); + }); + } + + /** + * Revoke the update permission on the role + */ + protected void revokeUpdateOnRole() { + tx(tx -> { + tx.roleDao().revokePermissions(role(), role(), UPDATE_PERM); + }); + } + + /** + * Get a client handler that gets the role permissions on the tested element + * @return client handler + */ + protected abstract ClientHandler getRolePermissions(); + + /** + * Get a client handler that grants the role permissions on the tested element + * @param request request + * @return client handler + */ + protected abstract ClientHandler grantRolePermissions(ObjectPermissionGrantRequest request); + + /** + * Get a client handler that revokes the role permissions from the tested element + * @param request request + * @return client handler + */ + protected abstract ClientHandler revokeRolePermissions(ObjectPermissionRevokeRequest request); +}