diff --git a/modules/rest-api/src/com/haulmont/addon/restapi/api/service/PermissionsControllerManager.java b/modules/rest-api/src/com/haulmont/addon/restapi/api/service/PermissionsControllerManager.java index 758e649..589e11c 100644 --- a/modules/rest-api/src/com/haulmont/addon/restapi/api/service/PermissionsControllerManager.java +++ b/modules/rest-api/src/com/haulmont/addon/restapi/api/service/PermissionsControllerManager.java @@ -116,40 +116,21 @@ public EffectiveRoleInfo getEffectiveRole(EffectiveRoleRequestParams params) { public EffectiveRoleInfo createEffectiveRoleInfo(RoleDefinition role, EffectiveRoleRequestParams params) { EffectiveRoleInfo roleInfo = new EffectiveRoleInfo(); - DefaultValuesInfo defaultValues = roleInfo.getDefaultValues(); ExplicitPermissionsInfo explicitPermissionsInfo = roleInfo.getExplicitPermissions(); if (params.isEntities()) { explicitPermissionsInfo.setEntities(new ArrayList<>()); role.entityPermissions().getExplicitPermissions().forEach((key, value) -> explicitPermissionsInfo.getEntities().add(new ShortPermissionInfo(key, value))); - defaultValues.setEntityCreate(role.entityPermissions().getDefaultEntityCreateAccess() != null ? - role.entityPermissions().getDefaultEntityCreateAccess().getId() : - null); - defaultValues.setEntityRead(role.entityPermissions().getDefaultEntityReadAccess() != null ? - role.entityPermissions().getDefaultEntityReadAccess().getId() : - null); - defaultValues.setEntityUpdate(role.entityPermissions().getDefaultEntityUpdateAccess() != null ? - role.entityPermissions().getDefaultEntityUpdateAccess().getId() : - null); - defaultValues.setEntityDelete(role.entityPermissions().getDefaultEntityDeleteAccess() != null ? - role.entityPermissions().getDefaultEntityDeleteAccess().getId() : - null); } if (params.isEntityAttributes()) { explicitPermissionsInfo.setEntityAttributes(new ArrayList<>()); role.entityAttributePermissions().getExplicitPermissions().forEach((key, value) -> explicitPermissionsInfo.getEntityAttributes().add(new ShortPermissionInfo(key, value))); - defaultValues.setEntityAttribute(role.entityAttributePermissions().getDefaultEntityAttributeAccess() != null ? - role.entityAttributePermissions().getDefaultEntityAttributeAccess().getId() : - null); } if (params.isSpecific()) { explicitPermissionsInfo.setSpecific(new ArrayList<>()); role.specificPermissions().getExplicitPermissions().forEach((key, value) -> explicitPermissionsInfo.getSpecific().add(new ShortPermissionInfo(key, value))); - defaultValues.setSpecific(role.specificPermissions().getDefaultSpecificAccess() != null ? - role.specificPermissions().getDefaultSpecificAccess().getId() : - null); } roleInfo.setUndefinedPermissionPolicy(rolesService.getPermissionUndefinedAccessPolicy().name()); diff --git a/modules/rest-api/src/com/haulmont/addon/restapi/api/service/filter/data/DefaultValuesInfo.java b/modules/rest-api/src/com/haulmont/addon/restapi/api/service/filter/data/DefaultValuesInfo.java deleted file mode 100644 index 8fd26a3..0000000 --- a/modules/rest-api/src/com/haulmont/addon/restapi/api/service/filter/data/DefaultValuesInfo.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2008-2020 Haulmont. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.haulmont.addon.restapi.api.service.filter.data; - -import com.fasterxml.jackson.annotation.JsonInclude; - -@JsonInclude(JsonInclude.Include.NON_NULL) -public class DefaultValuesInfo { - - private Integer entityCreate; - private Integer entityRead; - private Integer entityUpdate; - private Integer entityDelete; - private Integer entityAttribute; - private Integer specific; - - public DefaultValuesInfo() { - } - - public Integer getEntityCreate() { - return entityCreate; - } - - public void setEntityCreate(Integer entityCreate) { - this.entityCreate = entityCreate; - } - - public Integer getEntityRead() { - return entityRead; - } - - public void setEntityRead(Integer entityRead) { - this.entityRead = entityRead; - } - - public Integer getEntityUpdate() { - return entityUpdate; - } - - public void setEntityUpdate(Integer entityUpdate) { - this.entityUpdate = entityUpdate; - } - - public Integer getEntityDelete() { - return entityDelete; - } - - public void setEntityDelete(Integer entityDelete) { - this.entityDelete = entityDelete; - } - - public Integer getEntityAttribute() { - return entityAttribute; - } - - public void setEntityAttribute(Integer entityAttribute) { - this.entityAttribute = entityAttribute; - } - - public Integer getSpecific() { - return specific; - } - - public void setSpecific(Integer specific) { - this.specific = specific; - } -} diff --git a/modules/rest-api/src/com/haulmont/addon/restapi/api/service/filter/data/EffectiveRoleInfo.java b/modules/rest-api/src/com/haulmont/addon/restapi/api/service/filter/data/EffectiveRoleInfo.java index 665d8c4..9f8010c 100644 --- a/modules/rest-api/src/com/haulmont/addon/restapi/api/service/filter/data/EffectiveRoleInfo.java +++ b/modules/rest-api/src/com/haulmont/addon/restapi/api/service/filter/data/EffectiveRoleInfo.java @@ -21,8 +21,6 @@ public class EffectiveRoleInfo { private ExplicitPermissionsInfo explicitPermissions = new ExplicitPermissionsInfo(); - private DefaultValuesInfo defaultValues = new DefaultValuesInfo(); - private String undefinedPermissionPolicy = "DENY"; public EffectiveRoleInfo() { @@ -36,14 +34,6 @@ public void setExplicitPermissions(ExplicitPermissionsInfo explicitPermissions) this.explicitPermissions = explicitPermissions; } - public DefaultValuesInfo getDefaultValues() { - return defaultValues; - } - - public void setDefaultValues(DefaultValuesInfo defaultValues) { - this.defaultValues = defaultValues; - } - public String getUndefinedPermissionPolicy() { return undefinedPermissionPolicy; } diff --git a/test/restapi-demo/modules/core/src/com/haulmont/rest/demo/core/roles/RestFullAccessRole.java b/test/restapi-demo/modules/core/src/com/haulmont/rest/demo/core/roles/RestFullAccessRole.java index e702881..42ea482 100644 --- a/test/restapi-demo/modules/core/src/com/haulmont/rest/demo/core/roles/RestFullAccessRole.java +++ b/test/restapi-demo/modules/core/src/com/haulmont/rest/demo/core/roles/RestFullAccessRole.java @@ -10,31 +10,27 @@ /** * Role grants full access for REST API */ -@Role(name = RestFullAccessRole.NAME, securityScope = "REST") +@Role(name = RestFullAccessRole.NAME, securityScope = "REST", isSuper = true) public class RestFullAccessRole extends AnnotatedRoleDefinition { public static final String NAME = "rest-full-access"; @Override - @DefaultEntityAccess(allow = {EntityOp.CREATE, EntityOp.READ, EntityOp.UPDATE, EntityOp.DELETE}) public EntityPermissionsContainer entityPermissions() { return super.entityPermissions(); } @Override - @DefaultEntityAttributeAccess(EntityAttrAccess.MODIFY) public EntityAttributePermissionsContainer entityAttributePermissions() { return super.entityAttributePermissions(); } @Override - @DefaultSpecificAccess(Access.ALLOW) public SpecificPermissionsContainer specificPermissions() { return super.specificPermissions(); } @Override - @DefaultScreenAccess(Access.ALLOW) public ScreenPermissionsContainer screenPermissions() { return super.screenPermissions(); } diff --git a/test/restapi-demo/modules/core/src/com/haulmont/rest/demo/core/roles/RestTestAnonymousRole.java b/test/restapi-demo/modules/core/src/com/haulmont/rest/demo/core/roles/RestTestAnonymousRole.java index 22bfc46..d6cf87b 100644 --- a/test/restapi-demo/modules/core/src/com/haulmont/rest/demo/core/roles/RestTestAnonymousRole.java +++ b/test/restapi-demo/modules/core/src/com/haulmont/rest/demo/core/roles/RestTestAnonymousRole.java @@ -18,8 +18,8 @@ package com.haulmont.rest.demo.core.roles; import com.haulmont.cuba.security.app.role.AnnotatedRoleDefinition; -import com.haulmont.cuba.security.app.role.annotation.DefaultEntityAttributeAccess; import com.haulmont.cuba.security.app.role.annotation.EntityAccess; +import com.haulmont.cuba.security.app.role.annotation.EntityAttributeAccess; import com.haulmont.cuba.security.app.role.annotation.Role; import com.haulmont.cuba.security.entity.EntityAttrAccess; import com.haulmont.cuba.security.entity.EntityOp; @@ -36,13 +36,13 @@ public class RestTestAnonymousRole extends AnnotatedRoleDefinition { @Override - @EntityAccess(target = User.class, allow = {EntityOp.READ}) + @EntityAccess(entityClass = User.class, operations = {EntityOp.READ}) public EntityPermissionsContainer entityPermissions() { return super.entityPermissions(); } @Override - @DefaultEntityAttributeAccess(value = EntityAttrAccess.VIEW) + @EntityAttributeAccess(entityName = "*", view = "*") public EntityAttributePermissionsContainer entityAttributePermissions() { return super.entityAttributePermissions(); } diff --git a/test/restapi-demo/modules/portal/test/com/haulmont/rest/demo/http/rest/EntitiesControllerSecurityFT.java b/test/restapi-demo/modules/portal/test/com/haulmont/rest/demo/http/rest/EntitiesControllerSecurityFT.java index f88afd5..6c67bac 100644 --- a/test/restapi-demo/modules/portal/test/com/haulmont/rest/demo/http/rest/EntitiesControllerSecurityFT.java +++ b/test/restapi-demo/modules/portal/test/com/haulmont/rest/demo/http/rest/EntitiesControllerSecurityFT.java @@ -482,63 +482,105 @@ private void createDbUserRoles() throws SQLException { private void createDbRoles() throws SQLException { //read-only role. can read colours, can't read cars colorReadRoleId = dirtyData.createRoleUuid(); - executePrepared("insert into sec_role(id, name, security_scope, default_entity_read_access) " + - "values(?, ?, ?, ?)", + executePrepared("insert into sec_role(id, name, security_scope) " + + "values(?, ?, ?)", colorReadRoleId, "colorReadRole", - "REST", - 1 + "REST" ); + executePrepared("insert into sec_permission(id, role_id, permission_type, target, value_) " + + "values(?, ?, ?, ?, ?)", + dirtyData.createPermissionUuid(), + colorReadRoleId, + PermissionType.ENTITY_OP.getId(), + "*:read", + 1); + //read_only role. can update colours, can't update cars colorUpdateRoleId = dirtyData.createRoleUuid(); - executePrepared("insert into sec_role(id, name, security_scope, default_entity_read_access) " + - "values(?, ?, ?, ?)", + executePrepared("insert into sec_role(id, name, security_scope) " + + "values(?, ?, ?)", colorUpdateRoleId, "colorUpdateRole", - "REST", - 1 + "REST" ); + executePrepared("insert into sec_permission(id, role_id, permission_type, target, value_) " + + "values(?, ?, ?, ?, ?)", + dirtyData.createPermissionUuid(), + colorUpdateRoleId, + PermissionType.ENTITY_OP.getId(), + "*:read", + 1); + //read-only role. can create colours colorCreateRoleId = dirtyData.createRoleUuid(); - executePrepared("insert into sec_role(id, name, security_scope, default_entity_read_access) " + - "values(?, ?, ?, ?)", + executePrepared("insert into sec_role(id, name, security_scope) " + + "values(?, ?, ?)", colorCreateRoleId, "colorCreateRole", - "REST", - 1 + "REST" ); + executePrepared("insert into sec_permission(id, role_id, permission_type, target, value_) " + + "values(?, ?, ?, ?, ?)", + dirtyData.createPermissionUuid(), + colorCreateRoleId, + PermissionType.ENTITY_OP.getId(), + "*:read", + 1); + //read-only role. can delete colours colorDeleteRoleId = dirtyData.createRoleUuid(); - executePrepared("insert into sec_role(id, name, security_scope, default_entity_read_access) " + - "values(?, ?, ?, ?)", + executePrepared("insert into sec_role(id, name, security_scope) " + + "values(?, ?, ?)", colorDeleteRoleId, "colorDeleteRole", - "REST", - 1 + "REST" ); + executePrepared("insert into sec_permission(id, role_id, permission_type, target, value_) " + + "values(?, ?, ?, ?, ?)", + dirtyData.createPermissionUuid(), + colorDeleteRoleId, + PermissionType.ENTITY_OP.getId(), + "*:read", + 1); + //read-only role for attributes access tests carReadRoleId = dirtyData.createRoleUuid(); - executePrepared("insert into sec_role(id, name, security_scope, default_entity_read_access) " + - "values(?, ?, ?, ?)", + executePrepared("insert into sec_role(id, name, security_scope) " + + "values(?, ?, ?)", carReadRoleId, "carReadRole", - "REST", - 1 + "REST" ); + executePrepared("insert into sec_permission(id, role_id, permission_type, target, value_) " + + "values(?, ?, ?, ?, ?)", + dirtyData.createPermissionUuid(), + carReadRoleId, + PermissionType.ENTITY_OP.getId(), + "*:read", + 1); + //read-only role, prohibiting viewing the colors noColorReadRoleId = dirtyData.createRoleUuid(); - executePrepared("insert into sec_role(id, name, security_scope, default_entity_read_access) " + - "values(?, ?, ?, ?)", + executePrepared("insert into sec_role(id, name, security_scope) " + + "values(?, ?, ?)", noColorReadRoleId, "noColorReadRole", - "REST", - 1 + "REST" ); + + executePrepared("insert into sec_permission(id, role_id, permission_type, target, value_) " + + "values(?, ?, ?, ?, ?)", + dirtyData.createPermissionUuid(), + noColorReadRoleId, + PermissionType.ENTITY_OP.getId(), + "*:read", + 1); } private void createDbData() throws SQLException { diff --git a/test/restapi-demo/modules/portal/test/com/haulmont/rest/demo/http/rest/PermissionsControllerFT.java b/test/restapi-demo/modules/portal/test/com/haulmont/rest/demo/http/rest/PermissionsControllerFT.java index 14b7bda..4474e8a 100644 --- a/test/restapi-demo/modules/portal/test/com/haulmont/rest/demo/http/rest/PermissionsControllerFT.java +++ b/test/restapi-demo/modules/portal/test/com/haulmont/rest/demo/http/rest/PermissionsControllerFT.java @@ -22,6 +22,7 @@ import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Collection; +import java.util.List; import java.util.UUID; import static com.haulmont.rest.demo.http.rest.RestTestUtils.*; @@ -67,7 +68,7 @@ public void getPermissions() throws Exception { assertEquals(HttpStatus.SC_OK, statusCode(response)); ReadContext ctx = parseResponse(response); assertTrue(ctx.read("$").size() > 0); - assertEquals("MODIFY", ctx.read("$[?(@.target == 'ref$Currency.name')].value").iterator().next()); + assertEquals("MODIFY", ctx.read("$[?(@.target == 'ref$Currency:name')].value").iterator().next()); assertEquals("DENY", ctx.read("$[?(@.target == 'ref_Car:update')].value").iterator().next()); } } @@ -78,13 +79,9 @@ public void getEffectiveEntitiesPermissions() throws Exception { try (CloseableHttpResponse response = sendGet(url, oauthToken, null)) { assertEquals(HttpStatus.SC_OK, statusCode(response)); ReadContext ctx = parseResponse(response); - assertEquals(1, ctx.read("$.explicitPermissions.entities").size()); - assertEquals("ref_Car:update", ctx.read("$.explicitPermissions.entities[0].target")); - assertEquals(0, (int) ctx.read("$.explicitPermissions.entities[0].value")); - assertEquals(0, (int) ctx.read("$.defaultValues.entityCreate")); - assertEquals(1, (int) ctx.read("$.defaultValues.entityRead")); - assertEquals(0, (int) ctx.read("$.defaultValues.entityUpdate")); - assertEquals(0, (int) ctx.read("$.defaultValues.entityDelete")); + assertEquals(2, ctx.read("$.explicitPermissions.entities").size()); + assertEquals(0, (int) ctx.read("$.explicitPermissions.entities[?(@.target == 'ref_Car:update')].value", List.class).get(0)); + assertEquals(1, (int) ctx.read("$.explicitPermissions.entities[?(@.target == '*:read')].value", List.class).get(0)); assertEquals("DENY", ctx.read("$.undefinedPermissionPolicy")); } } @@ -96,9 +93,8 @@ public void getEffectiveAttributesPermissions() throws Exception { assertEquals(HttpStatus.SC_OK, statusCode(response)); ReadContext ctx = parseResponse(response); assertEquals(1, ctx.read("$.explicitPermissions.entityAttributes").size()); - assertEquals("ref$Currency.name", ctx.read("$.explicitPermissions.entityAttributes[0].target")); + assertEquals("ref$Currency:name", ctx.read("$.explicitPermissions.entityAttributes[0].target")); assertEquals(2, (int) ctx.read("$.explicitPermissions.entityAttributes[0].value")); - assertEquals(0, (int) ctx.read("$.defaultValues.entityAttribute")); assertEquals("DENY", ctx.read("$.undefinedPermissionPolicy")); } } @@ -119,15 +115,12 @@ private void prepareDb() throws SQLException { ); roleId = dirtyData.createRoleUuid(); - executePrepared("insert into sec_role(id, role_type, name, security_scope, " + - "default_entity_create_access, default_entity_read_access, " + - "default_entity_update_access, default_entity_delete_access," + - "default_entity_attr_access) values(?, ?, ?, ?, ?, ?, ?, ?, ?)", + executePrepared("insert into sec_role(id, role_type, name, security_scope)" + + " values(?, ?, ?, ?)", roleId, RoleType.READONLY.getId(), "testRole", - "REST", - 0, 1, 0, 0, 0 + "REST" ); int ALLOW = 1; @@ -154,6 +147,14 @@ private void prepareDb() throws SQLException { DENY ); + executePrepared("insert into sec_permission(id, role_id, permission_type, target, value_) values(?, ?, ?, ?, ?)", + dirtyData.createPermissionUuid(), + roleId, + PermissionType.ENTITY_OP.getId(), + "*:read", + ALLOW + ); + //testRole forbids currencies browser screen UUID currenciesScreenPrmsId = dirtyData.createPermissionUuid(); executePrepared("insert into sec_permission(id, role_id, permission_type, target, value_) values(?, ?, ?, ?, ?)", @@ -164,13 +165,11 @@ private void prepareDb() throws SQLException { DENY ); - //testRole forbids currencies browser screen - UUID entityAttrModifyAllowPrmsId = dirtyData.createPermissionUuid(); executePrepared("insert into sec_permission(id, role_id, permission_type, target, value_) values(?, ?, ?, ?, ?)", - entityAttrModifyAllowPrmsId, + dirtyData.createPermissionUuid(), roleId, PermissionType.ENTITY_ATTR.getId(), - "ref$Currency.name", + "ref$Currency:name", PROPERTY_MODIFY ); @@ -181,7 +180,6 @@ private void prepareDb() throws SQLException { testUserId, roleId ); - } private void executePrepared(String sql, Object... params) throws SQLException { diff --git a/test/restapi-demo/modules/portal/test/spec/rest/demo/rest/StrictlyDenyingRoleEntityControllerFT.groovy b/test/restapi-demo/modules/portal/test/spec/rest/demo/rest/StrictlyDenyingRoleEntityControllerFT.groovy deleted file mode 100644 index cd625a0..0000000 --- a/test/restapi-demo/modules/portal/test/spec/rest/demo/rest/StrictlyDenyingRoleEntityControllerFT.groovy +++ /dev/null @@ -1,84 +0,0 @@ -package spec.rest.demo.rest - -import com.haulmont.cuba.security.entity.PermissionType -import com.haulmont.cuba.security.entity.RoleType -import com.haulmont.rest.demo.http.api.DataSet -import groovy.sql.Sql -import org.apache.http.HttpStatus -import spock.lang.Specification - -import static org.hamcrest.CoreMatchers.notNullValue -import static org.hamcrest.CoreMatchers.nullValue -import static spec.rest.demo.rest.DataUtils.* -import static spec.rest.demo.rest.DbUtils.getSql -import static spec.rest.demo.rest.RestSpecsUtils.createRequest -import static spec.rest.demo.rest.RestSpecsUtils.getAuthToken - -class StrictlyDenyingRoleEntityControllerFT extends Specification { - - private Sql sql - private DataSet dirtyData = new DataSet() - - private String userPassword = "password" - private String userLogin = "user1" - private String userToken - - private UUID carId - - void setup() { - sql = getSql() as Sql - - def groupId = createGroup(dirtyData, sql, 'Group') - - UUID userId = createUser(dirtyData, sql, - userLogin, userPassword, groupId) - - def roleId = dirtyData.createRoleUuid() - sql.dataSet('sec_role').add( - id: roleId, - version: 1, - name: 'TestStrictDenyingRole', - security_scope: 'REST', - default_entity_attr_access: 0 - ) - - //access REST API - createPermission(dirtyData, sql, roleId, PermissionType.SPECIFIC, 'cuba.restApi.enabled', 1) - - //read ref_Car - createPermission(dirtyData, sql, roleId, PermissionType.ENTITY_OP, 'ref_Car:read', 1) - - //read ref_Car vin attribute - createPermission(dirtyData, sql, roleId, PermissionType.ENTITY_ATTR, 'ref_Car:vin', 1) - - createUserRole(dirtyData, sql, userId, roleId) - - UUID colorId = createColor(dirtyData, sql, 'Black') - - carId = createCarWithColour(dirtyData, sql, 'carVin1', colorId) - - userToken = getAuthToken(userLogin, userPassword) - } - - void cleanup() { - dirtyData.cleanup(sql.connection) - if (sql != null) { - sql.close() - } - } - - def "load car with restricted attributes. only vin attribute is allowed"() { - when: - - def request = createRequest(userToken).param('view', 'carEdit') - def response = request.with().get("/entities/ref_Car/$carId") - - then: - - response.then().statusCode(HttpStatus.SC_OK) - .body('vin', notNullValue()) - .body("id", notNullValue()) - .body("createTs", nullValue()) - .body("colour", nullValue()) - } -}