PL-8064 Define access group constraints on @MappedSuperclasses

This commit is contained in:
Andrey Subbotin 2017-04-04 16:43:20 +04:00
parent f72984e0b1
commit 63d8dde501
3 changed files with 256 additions and 14 deletions

View File

@ -0,0 +1,231 @@
/*
* Copyright (c) 2008-2017 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.cuba.security;
import com.haulmont.cuba.core.EntityManager;
import com.haulmont.cuba.core.Transaction;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.security.app.LoginWorker;
import com.haulmont.cuba.security.entity.*;
import com.haulmont.cuba.security.global.LoginException;
import com.haulmont.cuba.security.global.UserSession;
import com.haulmont.cuba.testsupport.TestContainer;
import com.haulmont.cuba.testsupport.TestUserSessionSource;
import org.junit.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class ParentClassConstraintTest {
@ClassRule
public static TestContainer cont = TestContainer.Common.INSTANCE;
private Group parentGroup;
private Group constraintGroup1, constraintGroup2, constraintGroup3;
private Constraint constraint1, constraint2, constraint3, constraint4;
private User constraintUser1, constraintUser2, constraintUser3;
private SearchFolder searchFolder1, searchFolder2;
private PasswordEncryption passwordEncryption;
private static final String PASSWORD = "1";
@Before
public void setUp() {
passwordEncryption = AppBeans.get(PasswordEncryption.class);
Transaction tx = cont.persistence().createTransaction();
try {
EntityManager em = cont.persistence().getEntityManager();
parentGroup = new Group();
parentGroup.setName("parentGroup");
em.persist(parentGroup);
constraintGroup1 = new Group();
constraintGroup1.setName("constraintGroup1");
em.persist(constraintGroup1);
constraint1 = new Constraint();
constraint1.setEntityName("sys$Folder");
constraint1.setCheckType(ConstraintCheckType.DATABASE);
constraint1.setOperationType(ConstraintOperationType.READ);
constraint1.setWhereClause("{E}.name = 'folder1'");
constraint1.setGroup(constraintGroup1);
em.persist(constraint1);
constraintGroup2 = new Group();
constraintGroup2.setName("constraintGroup2");
em.persist(constraintGroup2);
constraint2 = new Constraint();
constraint2.setEntityName("sys$Folder");
constraint2.setCheckType(ConstraintCheckType.DATABASE);
constraint2.setOperationType(ConstraintOperationType.READ);
constraint2.setWhereClause("{E}.name = 'folder1'");
constraint2.setGroup(constraintGroup2);
em.persist(constraint2);
constraint3 = new Constraint();
constraint3.setEntityName("sec$SearchFolder");
constraint3.setCheckType(ConstraintCheckType.DATABASE);
constraint3.setOperationType(ConstraintOperationType.READ);
constraint3.setWhereClause("{E}.name = 'folder2'");
constraint3.setGroup(constraintGroup2);
em.persist(constraint3);
constraintGroup3 = new Group();
constraintGroup3.setName("constraintGroup3");
em.persist(constraintGroup3);
constraint4 = new Constraint();
constraint4.setEntityName("sys$StandardEntity");
constraint4.setCheckType(ConstraintCheckType.DATABASE);
constraint4.setOperationType(ConstraintOperationType.READ);
constraint4.setWhereClause("{E}.createTs is null");
constraint4.setGroup(constraintGroup3);
em.persist(constraint4);
constraintUser1 = new User();
constraintUser1.setLogin("constraintUser1");
constraintUser1.setPassword(passwordEncryption.getPasswordHash(constraintUser1.getId(), PASSWORD));
constraintUser1.setGroup(constraintGroup1);
em.persist(constraintUser1);
constraintUser2 = new User();
constraintUser2.setLogin("constraintUser2");
constraintUser2.setPassword(passwordEncryption.getPasswordHash(constraintUser2.getId(), PASSWORD));
constraintUser2.setGroup(constraintGroup2);
em.persist(constraintUser2);
constraintUser3 = new User();
constraintUser3.setLogin("constraintUser3");
constraintUser3.setPassword(passwordEncryption.getPasswordHash(constraintUser3.getId(), PASSWORD));
constraintUser3.setGroup(constraintGroup3);
em.persist(constraintUser3);
searchFolder1 = new SearchFolder();
searchFolder1.setName("folder1");
em.persist(searchFolder1);
searchFolder2 = new SearchFolder();
searchFolder2.setName("folder2");
em.persist(searchFolder2);
tx.commit();
} finally {
tx.end();
}
}
@Test
public void testConstraintsOnParentClass() throws LoginException {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<SearchFolder> loadContext = new LoadContext<>(SearchFolder.class).setView(View.LOCAL);
loadContext.setQueryString("select f from sec$SearchFolder f");
List resultList = dataManager.loadList(loadContext);
assertEquals(2, resultList.size());
LoginWorker lw = AppBeans.get(LoginWorker.NAME);
UserSession userSession = lw.login("constraintUser1", passwordEncryption.getPlainHash(PASSWORD), Locale.getDefault());
assertNotNull(userSession);
UserSessionSource uss = AppBeans.get(UserSessionSource.class);
UserSession savedUserSession = uss.getUserSession();
((TestUserSessionSource) uss).setUserSession(userSession);
try {
dataManager = AppBeans.get(DataManager.NAME);
dataManager = dataManager.secure();
loadContext = new LoadContext<>(SearchFolder.class).setView(View.LOCAL);
loadContext.setQueryString("select f from sec$SearchFolder f");
resultList = dataManager.loadList(loadContext);
assertEquals(1, resultList.size());
} finally {
((TestUserSessionSource) uss).setUserSession(savedUserSession);
}
}
@Test
public void testConstraintsOnParentAndCurrentMetaClass() throws LoginException {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<SearchFolder> loadContext = new LoadContext<>(SearchFolder.class).setView(View.LOCAL);
loadContext.setQueryString("select f from sec$SearchFolder f");
List resultList = dataManager.loadList(loadContext);
assertEquals(2, resultList.size());
LoginWorker lw = AppBeans.get(LoginWorker.NAME);
UserSession userSession = lw.login("constraintUser2", passwordEncryption.getPlainHash(PASSWORD), Locale.getDefault());
assertNotNull(userSession);
UserSessionSource uss = AppBeans.get(UserSessionSource.class);
UserSession savedUserSession = uss.getUserSession();
((TestUserSessionSource) uss).setUserSession(userSession);
try {
dataManager = AppBeans.get(DataManager.NAME);
dataManager = dataManager.secure();
loadContext = new LoadContext<>(SearchFolder.class).setView(View.LOCAL);
loadContext.setQueryString("select f from sec$SearchFolder f");
resultList = dataManager.loadList(loadContext);
assertEquals(0, resultList.size());
} finally {
((TestUserSessionSource) uss).setUserSession(savedUserSession);
}
}
@Test
public void testConstraintsOnMappedSuperClass() throws LoginException {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<SearchFolder> loadContext = new LoadContext<>(SearchFolder.class).setView(View.LOCAL);
loadContext.setQueryString("select f from sec$SearchFolder f");
List resultList = dataManager.loadList(loadContext);
assertEquals(2, resultList.size());
LoginWorker lw = AppBeans.get(LoginWorker.NAME);
UserSession userSession = lw.login("constraintUser3", passwordEncryption.getPlainHash(PASSWORD), Locale.getDefault());
assertNotNull(userSession);
UserSessionSource uss = AppBeans.get(UserSessionSource.class);
UserSession savedUserSession = uss.getUserSession();
((TestUserSessionSource) uss).setUserSession(userSession);
try {
dataManager = AppBeans.get(DataManager.NAME);
dataManager = dataManager.secure();
loadContext = new LoadContext<>(SearchFolder.class).setView(View.LOCAL);
loadContext.setQueryString("select f from sec$SearchFolder f");
resultList = dataManager.loadList(loadContext);
assertEquals(0, resultList.size());
} finally {
((TestUserSessionSource) uss).setUserSession(savedUserSession);
}
}
@After
public void tearDown() throws Exception {
cont.deleteRecord("SEC_USER", constraintUser1.getId(), constraintUser2.getId(), constraintUser3.getId());
cont.deleteRecord("SEC_CONSTRAINT", constraint1.getId(), constraint2.getId(), constraint3.getId(), constraint4.getId());
cont.deleteRecord("SEC_GROUP", parentGroup.getId(), constraintGroup1.getId(), constraintGroup2.getId(), constraintGroup3.getId());
cont.deleteRecord("SEC_SEARCH_FOLDER", "FOLDER_ID", searchFolder1.getId(), searchFolder2.getId());
cont.deleteRecord("SYS_FOLDER", searchFolder1.getId(), searchFolder2.getId());
}
}

View File

@ -39,6 +39,7 @@ import javax.inject.Inject;
import java.text.ParseException;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static com.haulmont.cuba.security.entity.ConstraintOperationType.ALL;
import static com.haulmont.cuba.security.entity.ConstraintOperationType.CUSTOM;
@ -171,26 +172,35 @@ public class SecurityImpl implements Security {
@Override
public boolean hasConstraints(MetaClass metaClass) {
UserSession userSession = userSessionSource.getUserSession();
String mainMetaClassName = extendedEntities.getOriginalOrThisMetaClass(metaClass).getName();
return userSession.hasConstraints(mainMetaClassName);
List<ConstraintData> constraints = getConstraints(metaClass);
return !constraints.isEmpty();
}
@Override
public boolean hasInMemoryConstraints(MetaClass metaClass, ConstraintOperationType... operationTypes) {
UserSession userSession = userSessionSource.getUserSession();
String mainMetaClassName = extendedEntities.getOriginalOrThisMetaClass(metaClass).getName();
List<ConstraintData> constraints = userSession.getConstraints(mainMetaClassName, constraint ->
constraint.getCheckType().memory() && constraint.getOperationType() != null
&& Arrays.asList(operationTypes).contains(constraint.getOperationType())
List<ConstraintData> constraints = getConstraints(metaClass, constraint ->
constraint.getCheckType().memory() && constraint.getOperationType() != null
&& Arrays.asList(operationTypes).contains(constraint.getOperationType())
);
return !constraints.isEmpty();
}
protected List<ConstraintData> getConstraints(MetaClass metaClass, Predicate<ConstraintData> predicate) {
return getConstraints(metaClass).stream()
.filter(predicate)
.collect(Collectors.toList());
}
protected List<ConstraintData> getConstraints(MetaClass metaClass) {
UserSession userSession = userSessionSource.getUserSession();
String mainMetaClassName = extendedEntities.getOriginalOrThisMetaClass(metaClass).getName();
return userSession.getConstraints(mainMetaClassName, predicate);
MetaClass mainMetaClass = extendedEntities.getOriginalOrThisMetaClass(metaClass);
List<ConstraintData> constraints = new ArrayList<>();
constraints.addAll(userSession.getConstraints(mainMetaClass.getName()));
for (MetaClass parent : mainMetaClass.getAncestors()) {
constraints.addAll(userSession.getConstraints(parent.getName()));
}
return constraints;
}
protected boolean isPermitted(Entity entity, Predicate<ConstraintData> predicate) {
@ -216,7 +226,7 @@ public class SecurityImpl implements Security {
}
} catch (Exception e) {
log.error("An error occurred while applying constraint's Groovy script. The entity has been filtered out." +
"Entity class [{}]. Entity [{}].", metaClassName, entity.getId(), e);
"Entity class [{}]. Entity [{}].", metaClassName, entity.getId(), e);
return false;
}
}
@ -236,7 +246,7 @@ public class SecurityImpl implements Security {
/**
* Override if you need specific context variables in Groovy constraints.
*
* @param context passed to Groovy evaluator
* @param context passed to Groovy evaluator
*/
protected void fillGroovyConstraintsContext(Map<String, Object> context) {
}

View File

@ -20,6 +20,7 @@ package com.haulmont.cuba.gui.app.security.constraint.edit;
import com.google.common.base.Strings;
import com.haulmont.bali.util.Dom4j;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.cuba.core.entity.BaseGenericIdEntity;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.core.global.filter.GroovyGenerator;
import com.haulmont.cuba.core.global.filter.SecurityJpqlGenerator;
@ -131,8 +132,8 @@ public class ConstraintEditor extends AbstractEditor<Constraint> {
Map<String, Object> options = new TreeMap<>();
MessageTools messageTools = AppBeans.get(MessageTools.NAME);
entities = new HashMap<>();
for (MetaClass metaClass : metadata.getTools().getAllPersistentMetaClasses()) {
if (extendedEntities.getExtendedClass(metaClass) == null) {
for (MetaClass metaClass : metadata.getSession().getClasses()) {
if (extendedEntities.getExtendedClass(metaClass) == null && BaseGenericIdEntity.class.isAssignableFrom(metaClass.getJavaClass())) {
MetaClass mainMetaClass = extendedEntities.getOriginalOrThisMetaClass(metaClass);
String originalName = mainMetaClass.getName();
options.put(messageTools.getEntityCaption(metaClass) + " (" + metaClass.getName() + ")", originalName);