Java tutorial
/*************************************************************** * This file is part of the [fleXive](R) framework. * * Copyright (c) 1999-2014 * UCS - unique computing solutions gmbh (http://www.ucs.at) * All rights reserved * * The [fleXive](R) project is free software; you can redistribute * it and/or modify it under the terms of the GNU Lesser General Public * License version 2.1 or higher as published by the Free Software Foundation. * * The GNU Lesser General Public License can be found at * http://www.gnu.org/licenses/lgpl.html. * A copy is found in the textfile LGPL.txt and important notices to the * license from the author are found in LICENSE.txt distributed with * these libraries. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * For further information about UCS - unique computing solutions gmbh, * please see the company website: http://www.ucs.at * * For further information about [fleXive](R), please see the * project website: http://www.flexive.org * * * This copyright notice MUST APPEAR in all copies of the file! ***************************************************************/ package com.flexive.tests.embedded.persistence; import com.flexive.shared.CacheAdmin; import com.flexive.shared.EJBLookup; import com.flexive.shared.FxContext; import com.flexive.shared.content.FxContent; import com.flexive.shared.content.FxPK; import com.flexive.shared.content.FxPermissionUtils; import com.flexive.shared.exceptions.*; import com.flexive.shared.interfaces.ACLEngine; import com.flexive.shared.interfaces.ContentEngine; import com.flexive.shared.interfaces.TypeEngine; import com.flexive.shared.interfaces.UserGroupEngine; import com.flexive.shared.search.FxResultSet; import com.flexive.shared.search.query.PropertyValueComparator; import com.flexive.shared.search.query.QueryOperatorNode; import com.flexive.shared.search.query.SqlQueryBuilder; import com.flexive.shared.security.*; import com.flexive.shared.structure.*; import com.flexive.shared.value.FxNoAccess; import com.flexive.shared.value.FxString; import com.flexive.shared.workflow.*; import com.flexive.tests.embedded.TestUser; import com.flexive.tests.embedded.TestUsers; import org.apache.commons.lang.RandomStringUtils; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.Arrays; import static com.flexive.shared.EJBLookup.getAclEngine; import static com.flexive.shared.EJBLookup.getContentEngine; import static com.flexive.shared.security.ACLPermission.*; import static com.flexive.tests.embedded.FxTestUtils.login; import static com.flexive.tests.embedded.FxTestUtils.logout; import static org.testng.Assert.*; /** * Testcase for content related security * * @author Markus Plesser (markus.plesser@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at) * @version $Rev */ @Test(groups = { "ejb", "content", "security" }) public class ContentSecurityTest { UserGroup[] groups; FxType type; Workflow workflow; ACL typeACL, instanceACL, property1ACL, property2ACL, editACL, liveACL; TestUser user; final static FxString PROP1_VALUE = new FxString(false, "Property 1 test value"); final static FxString PROP2_VALUE = new FxString(false, "Property 2 test value"); @BeforeClass public void setup() throws FxApplicationException, FxLoginFailedException, FxAccountInUseException { user = TestUsers.createUser("SecurityTestUser", Role.BackendAccess); final UserGroupEngine ug = EJBLookup.getUserGroupEngine(); final ACLEngine ae = getAclEngine(); long mandator = TestUsers.getTestMandator(); FxContext.get().runAsSystem(); try { user.createUser(TestUsers.getTestMandator(), TestUsers.getEnglishLanguageId()); login(user); groups = new UserGroup[26]; for (int i = 0; i < 26; i++) groups[i] = ug.load(ug.create("UG" + (i + 1), "#FFFFFF", mandator)); typeACL = ae.load(ae.create("TYPE_" + RandomStringUtils.randomAlphanumeric(5), new FxString("Type ACL"), mandator, "#FFFFFF", "Type ACL", ACLCategory.STRUCTURE)); instanceACL = ae.load(ae.create("INSTANCE_" + RandomStringUtils.randomAlphanumeric(5), new FxString("Instance ACL"), mandator, "#FFFFFF", "Instance ACL", ACLCategory.INSTANCE)); property1ACL = ae.load(ae.create("PROPERTY1_" + RandomStringUtils.randomAlphanumeric(5), new FxString("Property1 ACL"), mandator, "#FFFFFF", "Property1 ACL", ACLCategory.STRUCTURE)); property2ACL = ae.load(ae.create("PROPERTY2_" + RandomStringUtils.randomAlphanumeric(5), new FxString("Property2 ACL"), mandator, "#FFFFFF", "Property2 ACL", ACLCategory.STRUCTURE)); editACL = ae.load(ae.create("EDIT_" + RandomStringUtils.randomAlphanumeric(5), new FxString("Edit ACL"), mandator, "#FFFFFF", "Edit ACL", ACLCategory.WORKFLOW)); liveACL = ae.load(ae.create("LIVE_" + RandomStringUtils.randomAlphanumeric(5), new FxString("Live ACL"), mandator, "#FFFFFF", "Live ACL", ACLCategory.WORKFLOW)); WorkflowEdit wfEdit = WorkflowEdit .createNew("Security_Workflow_" + RandomStringUtils.randomAlphanumeric(5)); wfEdit.getSteps().add(StepEdit.createNew(StepDefinition.EDIT_STEP_ID)); wfEdit.getSteps().add(StepEdit.createNew(StepDefinition.LIVE_STEP_ID)); long wf = EJBLookup.getWorkflowEngine().create(wfEdit); workflow = CacheAdmin.getEnvironment().getWorkflow(wf); Step edit, live; assertEquals(workflow.getSteps().size(), 2); if (workflow.getSteps().get(0).isLiveStep()) { live = workflow.getSteps().get(0); edit = workflow.getSteps().get(1); } else { live = workflow.getSteps().get(1); edit = workflow.getSteps().get(0); } EJBLookup.getWorkflowStepEngine().updateStep(edit.getId(), editACL.getId(), 1); EJBLookup.getWorkflowStepEngine().updateStep(live.getId(), liveACL.getId(), 1); workflow = CacheAdmin.getEnvironment().getWorkflow(wf); //create routes for the route test wfEdit = workflow.asEditable(); wfEdit.getRoutes().add(RouteEdit.createNew(getGroup(25), edit.getId(), live.getId())); wfEdit.getRoutes().add(RouteEdit.createNew(getGroup(26), live.getId(), edit.getId())); EJBLookup.getWorkflowEngine().update(wfEdit); workflow = CacheAdmin.getEnvironment().getWorkflow(wf); FxTypeEdit te = FxTypeEdit.createNew("SecurityTest"); te.setWorkflow(workflow); te.setACL(typeACL); long typeId = EJBLookup.getTypeEngine().save(te); EJBLookup.getAssignmentEngine().createProperty(typeId, FxPropertyEdit .createNew("P1", new FxString("Property 1"), new FxString("Hint"), FxMultiplicity.MULT_1_1, property1ACL, FxDataType.String1024) .setMultiLang(false), "/"); EJBLookup.getAssignmentEngine().createProperty(typeId, FxPropertyEdit .createNew("P2", new FxString("Property 2"), new FxString("Hint"), FxMultiplicity.MULT_0_1, property2ACL, FxDataType.String1024) .setMultiLang(false), "/"); type = CacheAdmin.getEnvironment().getType(typeId); } finally { FxContext.get().stopRunAsSystem(); } } /** * Get a usergroup based on its number * * @param number group number * @return group id */ private long getGroup(int number) { Assert.assertTrue(number > 0 && number < 27, "UserGroup has to be between 1 and 26, was: " + number); return groups[number - 1].getId(); } /** * Remove all created artifacts * * @throws FxApplicationException on errors * @throws FxLogoutFailedException on errors */ @AfterClass public void teardown() throws FxApplicationException, FxLogoutFailedException { final UserGroupEngine ug = EJBLookup.getUserGroupEngine(); FxContext.get().runAsSystem(); try { if (type != null) { getContentEngine().removeForType(type.getId()); EJBLookup.getTypeEngine().remove(type.getId()); } if (workflow != null) EJBLookup.getWorkflowEngine().remove(workflow.getId()); for (int i = 0; i < 26; i++) ug.remove(groups[i].getId()); final ACLEngine ae = getAclEngine(); ae.remove(typeACL.getId()); ae.remove(instanceACL.getId()); ae.remove(property1ACL.getId()); ae.remove(property2ACL.getId()); ae.remove(editACL.getId()); ae.remove(liveACL.getId()); } finally { FxContext.get().stopRunAsSystem(); } logout(); } /** * Assign a test matrix of permissions to an ACL * * @param matrix the matrix * @param acl the ACL * @throws FxApplicationException on errors */ private void assignMatrix(int matrix, ACL acl) throws FxApplicationException { FxContext.get().runAsSystem(); try { ArrayList<ACLAssignment> as = new ArrayList<ACLAssignment>(10); switch (matrix) { case 0: //Everything allowed as.add(ACLAssignment.createNew(acl, UserGroup.GROUP_EVERYONE, READ, EDIT, RELATE, CREATE, DELETE, EXPORT)); break; case 1: //Type and Instance matrix as.add(ACLAssignment.createNew(acl, groups[0].getId(), READ)); as.add(ACLAssignment.createNew(acl, groups[1].getId(), EDIT)); as.add(ACLAssignment.createNew(acl, groups[2].getId(), READ, EDIT)); as.add(ACLAssignment.createNew(acl, groups[3].getId(), CREATE, DELETE)); as.add(ACLAssignment.createNew(acl, groups[4].getId(), EDIT, CREATE, DELETE)); as.add(ACLAssignment.createNew(acl, groups[5].getId(), READ, EDIT, CREATE)); as.add(ACLAssignment.createNew(acl, groups[6].getId(), READ, EDIT, DELETE)); as.add(ACLAssignment.createNew(acl, groups[7].getId(), READ, EDIT, CREATE, DELETE)); as.add(ACLAssignment.createNew(acl, groups[8].getId(), READ, EDIT, RELATE, CREATE, DELETE)); as.add(ACLAssignment.createNew(acl, groups[9].getId(), READ, EDIT, RELATE, CREATE, DELETE, EXPORT)); break; case 2: //Property matrix as.add(ACLAssignment.createNew(acl, groups[10].getId(), READ)); as.add(ACLAssignment.createNew(acl, groups[11].getId(), EDIT)); as.add(ACLAssignment.createNew(acl, groups[12].getId(), READ, EDIT)); as.add(ACLAssignment.createNew(acl, groups[13].getId(), READ, EDIT, CREATE)); as.add(ACLAssignment.createNew(acl, groups[14].getId(), READ, EDIT, DELETE)); as.add(ACLAssignment.createNew(acl, groups[15].getId(), CREATE, DELETE)); as.add(ACLAssignment.createNew(acl, groups[16].getId(), READ, EDIT, CREATE, DELETE)); break; case 3: //Workflow Step matrix as.add(ACLAssignment.createNew(acl, groups[17].getId(), READ)); as.add(ACLAssignment.createNew(acl, groups[18].getId(), EDIT)); as.add(ACLAssignment.createNew(acl, groups[19].getId(), READ, EDIT)); as.add(ACLAssignment.createNew(acl, groups[20].getId(), READ, EDIT, CREATE)); as.add(ACLAssignment.createNew(acl, groups[21].getId(), READ, EDIT, DELETE)); as.add(ACLAssignment.createNew(acl, groups[22].getId(), CREATE, DELETE)); as.add(ACLAssignment.createNew(acl, groups[23].getId(), READ, EDIT, CREATE, DELETE)); break; case 4: //Workflow Route matrix - Edit as.add(ACLAssignment.createNew(acl, groups[24].getId(), READ, EDIT, CREATE, DELETE)); as.add(ACLAssignment.createNew(acl, groups[25].getId(), READ, EDIT)); break; case 5: //Workflow Route matrix - Live as.add(ACLAssignment.createNew(acl, groups[24].getId(), READ, EDIT)); as.add(ACLAssignment.createNew(acl, groups[25].getId(), READ, EDIT, CREATE)); break; default: Assert.assertFalse(true, "Invalid/unknown matrix: " + matrix); } getAclEngine().update(acl.getId(), null, null, null, null, as); } finally { FxContext.get().stopRunAsSystem(); } } /** * Assign one of the predefined groups to the test user * * @param grp group to assign * @throws FxApplicationException on errors */ private void assignGroup(long grp) throws FxApplicationException { // System.out.println("Before: "+ FxContext.getUserTicket()); FxContext.get().runAsSystem(); try { EJBLookup.getAccountEngine().setGroups(FxContext.getUserTicket().getUserId(), groups[((int) grp - 1)].getId()); } finally { FxContext.get().stopRunAsSystem(); } FxContext.get()._reloadUserTicket(); // System.out.println("After: "+ FxContext.getUserTicket()); // for(long g: FxContext.getUserTicket().getGroups()) // System.out.println("Group #"+g+": "+ EJBLookup.getUserGroupEngine().load(g).getName()); } /** * Check if the given group is contained in the list * * @param grp group to check for * @param groups list of groups * @return grp is contained in groups */ private boolean containsGroup(int grp, int... groups) { for (int group : groups) if (group == grp) return true; return false; } /** * Create a reference content * * @return reference FxContent instance * @throws FxApplicationException on errors */ private FxContent createReferenceContent() throws FxApplicationException { FxContent refContent; ContentEngine ce = getContentEngine(); try { FxContext.get().runAsSystem(); refContent = ce.initialize(type.getId()); refContent.setValue("/P1", PROP1_VALUE); refContent.setValue("/P2", PROP2_VALUE); refContent.setAclId(instanceACL.getId()); return ce.load(ce.save(refContent)); } finally { FxContext.get().stopRunAsSystem(); } } /** * Query for the given id to check if the searchengine results are identical to loading a content * * @param shouldExist should the requested id be found? * @param grp testgroup * @param id id of the instance * @param p2isNoAccess should P2 be FxNoAccess (if results are found) * @throws FxApplicationException on errors */ private void queryTest(boolean shouldExist, int grp, long id, boolean p2isNoAccess) throws FxApplicationException { final FxResultSet result = new SqlQueryBuilder().select("P1", "P2").enterSub(QueryOperatorNode.Operator.AND) .condition("ID", PropertyValueComparator.EQ, id).closeSub().getResult(); long expectedRows = shouldExist ? 1 : 0; Assert.assertTrue(expectedRows == result.getRowCount(), "Group: " + grp + ", Rows found: " + result.getRowCount() + ", expected: " + expectedRows); if (result.getRowCount() != 0) Assert.assertTrue(result.getResultRow(0).getFxValue("P2") instanceof FxNoAccess == p2isNoAccess, "Expected P2 " + (p2isNoAccess ? "" : "not ") + "to be FxNoaccess for group " + grp); } /** * Run a series of instance and type related tests * * @throws FxApplicationException on errors */ private void instanceTests() throws FxApplicationException { FxContent refContent = createReferenceContent(); ContentEngine ce = getContentEngine(); FxContent compare; //1..10: Load ref, error expected for 2,4,5 for (int grp = 1; grp <= 10; grp++) { assignGroup(grp); try { compare = ce.load(refContent.getPk()); assertEquals(refContent, compare); Assert.assertFalse(containsGroup(grp, 2, 4, 5), "Test should have failed for group " + grp); } catch (FxApplicationException e) { switch (grp) { case 2: case 4: case 5: //expected break; default: Assert.assertFalse(true, "Group " + grp + " should not have failed!"); } } queryTest(!containsGroup(grp, 2, 4, 5), grp, refContent.getPk().getId(), false); } //Save ref, error expected for 1 for (int grp = 1; grp <= 10; grp++) { if (containsGroup(grp, 2, 4, 5)) continue; assignGroup(grp); try { ce.save(refContent); Assert.assertFalse(containsGroup(grp, 1), "Test should have failed for group " + grp); } catch (FxApplicationException e) { switch (grp) { case 1: //expected break; default: Assert.assertFalse(true, "Group " + grp + " should not have failed!"); } } } //Create a clone of ref and remove it, error expected for 3, 6 for (int grp = 1; grp <= 10; grp++) { if (containsGroup(grp, 1, 2, 4, 5)) continue; FxContent clone; FxContext.get().runAsSystem(); try { clone = ce.load(ce.save(refContent.copyAsNewInstance())); } finally { FxContext.get().stopRunAsSystem(); } assignGroup(grp); try { ce.remove(clone.getPk()); Assert.assertFalse(containsGroup(grp, 3, 6), "Test should have failed for group " + grp); } catch (FxApplicationException e) { switch (grp) { case 3: case 6: //expected FxContext.get().runAsSystem(); try { ce.remove(clone.getPk()); } finally { FxContext.get().stopRunAsSystem(); } break; default: Assert.assertFalse(true, "Group " + grp + " should not have failed!"); } } } } /** * Test 1 - Type permissions * * @throws FxApplicationException on errors */ @Test public void test1_Type() throws FxApplicationException { //setup ACL test matrices assignMatrix(1, typeACL); assignMatrix(0, instanceACL); assignMatrix(0, property1ACL); assignMatrix(0, property2ACL); assignMatrix(0, editACL); assignMatrix(0, liveACL); useTypePermissions(false, false, false, true); //run the test series instanceTests(); } private void useTypePermissions(boolean useInstancePermissions, boolean usePropertyPermissions, boolean useStepPermissions, boolean useTypePermissions) throws FxApplicationException { FxTypeEdit te = type.asEditable(); te.setPermissions(FxPermissionUtils.encodeTypePermissions(useInstancePermissions, usePropertyPermissions, useStepPermissions, useTypePermissions)); FxContext.get().runAsSystem(); try { EJBLookup.getTypeEngine().save(te); } finally { FxContext.get().stopRunAsSystem(); } type = CacheAdmin.getEnvironment().getType(type.getId()); } /** * Test 2 - Instance permissions * * @throws FxApplicationException on errors */ @Test public void test2_Instance() throws FxApplicationException { //setup ACL test matrices assignMatrix(0, typeACL); assignMatrix(1, instanceACL); assignMatrix(0, property1ACL); assignMatrix(0, property2ACL); assignMatrix(0, editACL); assignMatrix(0, liveACL); useTypePermissions(true, false, false, false); instanceTests(); } /** * Test 3 - Type and Instance permissions * * @throws FxApplicationException on errors */ @Test public void test3_Type_Instance() throws FxApplicationException { //setup ACL test matrices assignMatrix(1, typeACL); assignMatrix(1, instanceACL); assignMatrix(0, property1ACL); assignMatrix(0, property2ACL); assignMatrix(0, editACL); assignMatrix(0, liveACL); useTypePermissions(true, false, false, true); instanceTests(); } /** * Test 4 - Property permissions * * @throws FxApplicationException on errors */ @Test public void test4_Properties() throws FxApplicationException { //setup ACL test matrices assignMatrix(0, typeACL); assignMatrix(0, instanceACL); assignMatrix(0, property1ACL); assignMatrix(2, property2ACL); assignMatrix(0, editACL); assignMatrix(0, liveACL); useTypePermissions(false, true, false, false); //run the test series FxContent refContent = createReferenceContent(); ContentEngine ce = getContentEngine(); FxContent compare; for (int grp = 11; grp <= 17; grp++) { assignGroup(grp); compare = ce.load(refContent.getPk()); //11..17: Load ref, P2 should be FxNoAccess for 12,16 if (containsGroup(grp, 12, 16)) { Assert.assertTrue(compare.getPropertyData("/P2").getValue() instanceof FxNoAccess, "/P2 expected to be FxNoAccess for group " + grp); Assert.assertNotSame(refContent, compare, "Group: " + grp); } else assertEquals(refContent, compare, "Group: " + grp); queryTest(true, grp, refContent.getPk().getId(), containsGroup(grp, 12, 16)); //11..17: change value, error expected for 11,16 try { compare.setValue("/P2", PROP1_VALUE); Assert.assertFalse(containsGroup(grp, 11, 16), "Group " + grp + " should have thrown an exception trying to override a FxNoAccess value"); } catch (FxRuntimeException e) { if (!containsGroup(grp, 11, 16)) Assert.assertTrue(true, "Group " + grp + " should be allowed to modify /P2"); else { //force change for next test FxContext.get().runAsSystem(); try { compare.setValue("/P2", PROP1_VALUE); } finally { FxContext.get().stopRunAsSystem(); } } } //11,13-15,17: save changed value, error expected for 11 if (containsGroup(grp, 11, 13, 14, 15, 17)) { try { FxPK pk = null; try { pk = ce.save(compare.copyAsNewInstance()); } finally { if (pk != null) { FxContext.get().runAsSystem(); try { ce.remove(pk); } finally { FxContext.get().stopRunAsSystem(); } } } Assert.assertFalse(containsGroup(grp, 11), "Group " + grp + " should have thrown an exception trying to save an instance"); } catch (FxApplicationException e) { if (!containsGroup(grp, 11)) Assert.assertTrue(true, "Group " + grp + " should be allowed to save a modified /P2"); } } //13-15,17: remove /P2 and save the instance, error expected for 13,14 if (containsGroup(grp, 13, 14, 15, 17)) { try { FxPK pk = null; try { FxContent co = compare.copyAsNewInstance(); FxContext.get().runAsSystem(); try { pk = ce.save(co); co = ce.load(pk); } finally { FxContext.get().stopRunAsSystem(); } co.remove("/P2"); ce.save(co); if (containsGroup(grp, 15, 17)) { //try to re-add /P2, error expected for 15 try { co.setValue("/P2", PROP2_VALUE); ce.save(co); if (grp == 15) Assert.assertFalse(true, "Group 15 should not be able to add /P2"); } catch (FxApplicationException e) { if (grp != 15) Assert.assertFalse(true, "Only Group 15 and not " + grp + " should not be able to add /P2"); } } } finally { if (pk != null) { FxContext.get().runAsSystem(); try { ce.remove(pk); } finally { FxContext.get().stopRunAsSystem(); } } } Assert.assertFalse(containsGroup(grp, 13, 14), "Group " + grp + " should have thrown an exception trying to save an instance with a removed /P2"); } catch (FxApplicationException e) { if (!containsGroup(grp, 13, 14)) Assert.assertTrue(true, "Group " + grp + " should be allowed to save an instance with a removed /P2"); } } } } /** * Test 5 - Workflow steps * * @throws FxApplicationException on errors */ @Test public void test5_WFSteps() throws FxApplicationException { //setup ACL test matrices assignMatrix(0, typeACL); assignMatrix(0, instanceACL); assignMatrix(0, property1ACL); assignMatrix(0, property2ACL); assignMatrix(3, editACL); assignMatrix(0, liveACL); useTypePermissions(false, false, true, false); //run the test series FxContent refContent = createReferenceContent(); ContentEngine ce = getContentEngine(); FxContent compare = null; for (int grp = 18; grp <= 24; grp++) { assignGroup(grp); //18..24: Load ref, error expected for 19,23 try { compare = ce.load(refContent.getPk()); Assert.assertFalse(containsGroup(grp, 19, 23), "Group " + grp + " should have thrown an exception trying to load the reference instance"); } catch (FxApplicationException e) { Assert.assertTrue(containsGroup(grp, 19, 23), "Group " + grp + " should not have thrown an exception trying to load the reference instance"); } queryTest(!containsGroup(grp, 19, 23), grp, refContent.getPk().getId(), false); //18,20-22,24: save ref instance, error expected for 18 if (!containsGroup(grp, 19, 23)) { try { ce.save(compare); Assert.assertFalse(containsGroup(grp, 18), "Group " + grp + " should have thrown an exception trying to save the reference instance"); } catch (FxApplicationException e) { Assert.assertTrue(containsGroup(grp, 18), "Group " + grp + " should not have thrown an exception trying to save the reference instance"); } } //20-22,24: clone ref. instance and save as supervisor, remove instance with test user - error expected for 20,21 if (!containsGroup(grp, 18, 19, 23)) { FxPK pk; try { FxContext.get().runAsSystem(); compare = refContent.copyAsNewInstance(); pk = ce.save(compare); } finally { FxContext.get().stopRunAsSystem(); } boolean removed = false; try { ce.remove(pk); Assert.assertFalse(containsGroup(grp, 20, 21), "Group " + grp + " should have thrown an exception trying to remove the reference instance"); removed = true; } catch (FxApplicationException e) { Assert.assertTrue(containsGroup(grp, 20, 21), "Group " + grp + " should not have thrown an exception trying to remove the reference instance"); } finally { if (!removed) { try { FxContext.get().runAsSystem(); ce.remove(pk); } finally { FxContext.get().stopRunAsSystem(); } } } } //18-24: create a new instance in edit step, error expected for 18,19,20,22 compare = ce.initialize(type.getId()); compare.setValue("/P1", PROP1_VALUE); compare.setValue("/P2", PROP2_VALUE); compare.setAclId(instanceACL.getId()); long stepId = -1; for (Step s : workflow.getSteps()) if (s.isEditStep()) stepId = s.getId(); Assert.assertFalse(stepId == -1, "Failed to find edit step!"); compare.setStepId(stepId); boolean created = false; FxPK pk = null; try { pk = ce.save(compare); Assert.assertFalse(containsGroup(grp, 18, 19, 20, 22), "Group " + grp + " should have thrown an exception trying to create an edit instance"); } catch (FxApplicationException e) { Assert.assertTrue(containsGroup(grp, 18, 19, 20, 22), "Group " + grp + " should not have thrown an exception trying to create an edit instance"); } finally { if (!created && pk != null) { try { FxContext.get().runAsSystem(); ce.remove(pk); } finally { FxContext.get().stopRunAsSystem(); } } } } } /** * Test 6 - Workflow routes * * @throws FxApplicationException on errors */ @Test public void test6_WFRoutes() throws FxApplicationException { //setup ACL test matrices assignMatrix(0, typeACL); assignMatrix(0, instanceACL); assignMatrix(0, property1ACL); assignMatrix(0, property2ACL); assignMatrix(4, editACL); assignMatrix(5, liveACL); //Routes are: //25: Edit->Live //26: Live->Edit useTypePermissions(false, false, true, false); //run the test series ContentEngine ce = getContentEngine(); FxContent ref; FxContent test; long edit = -1, live = -1; for (Step s : workflow.getSteps()) if (s.isEditStep()) edit = s.getId(); else if (s.isLiveStep()) live = s.getId(); Assert.assertTrue(edit != -1 && live != -1); for (int grp = 25; grp <= 26; grp++) { assignGroup(grp); //create instance in edit step, error expected for 26 ref = ce.initialize(type.getId()); ref.setValue("/P1", PROP1_VALUE); ref.setValue("/P2", PROP2_VALUE); ref.setAclId(instanceACL.getId()); ref.setStepId(edit); try { FxPK pk = ce.save(ref); Assert.assertTrue(grp == 25, "Only group 25 expected to succeed! Grp:" + grp); //cleanup FxContext.get().runAsSystem(); try { ce.remove(pk); } finally { FxContext.get().stopRunAsSystem(); } } catch (FxApplicationException e) { Assert.assertTrue(grp == 26, "Only group 26 expected to fail! Grp:" + grp); } //create instance in edit step, error expected for 25 ref.setStepId(live); try { FxPK pk = ce.save(ref); Assert.assertTrue(grp == 26, "Only group 26 expected to succeed! Grp:" + grp); //cleanup FxContext.get().runAsSystem(); try { ce.remove(pk); } finally { FxContext.get().stopRunAsSystem(); } } catch (FxApplicationException e) { Assert.assertTrue(grp == 25, "Only group 25 expected to fail! Grp:" + grp); } //use existing instance with step=edit and change it to live, error expected for 26 ref.setStepId(edit); FxContext.get().runAsSystem(); try { test = ce.load(ce.save(ref)); } finally { FxContext.get().stopRunAsSystem(); } try { test.setStepId(live); ce.save(test); Assert.assertTrue(grp == 25, "Only group 25 expected to succeed! Grp:" + grp); } catch (FxApplicationException e) { Assert.assertTrue(grp == 26, "Only group 26 expected to fail! Grp:" + grp + " Error: " + e.getMessage()); } finally { if (test != null) { FxContext.get().runAsSystem(); try { ce.remove(test.getPk()); } finally { FxContext.get().stopRunAsSystem(); } } } //use existing instance with step=live and change it to edit, error expected for 25 ref.setStepId(live); FxContext.get().runAsSystem(); try { test = ce.load(ce.save(ref)); } finally { FxContext.get().stopRunAsSystem(); } try { test.setStepId(edit); ce.save(test); Assert.assertTrue(grp == 26, "Only group 26 expected to succeed! Grp:" + grp); } catch (FxApplicationException e) { Assert.assertTrue(grp == 25, "Only group 25 expected to fail! Grp:" + grp + " Error: " + e.getMessage()); } finally { if (test != null) { FxContext.get().runAsSystem(); try { ce.remove(test.getPk()); } finally { FxContext.get().stopRunAsSystem(); } } } } } @Test(groups = { "ejb", "content", "security" }) public void multipleAclAssignment() throws FxApplicationException { final long acl1; final long acl2; FxPK pk; try { FxContext.get().runAsSystem(); useTypePermissions(true, false, true, true); acl1 = getAclEngine().create("multi_acl_group1", new FxString(""), TestUsers.getTestMandator(), "#000000", "", ACLCategory.INSTANCE); acl2 = getAclEngine().create("multi_acl_group2", new FxString(""), TestUsers.getTestMandator(), "#000000", "", ACLCategory.INSTANCE); getAclEngine().assign(acl1, getGroup(1), ACLPermission.READ, ACLPermission.EDIT); getAclEngine().assign(acl2, getGroup(2), ACLPermission.READ, ACLPermission.DELETE); FxContent content = getContentEngine().initialize("SecurityTest"); content.setValue("/p1", "Initial value"); content.setAclIds(Arrays.asList(acl1, acl2)); pk = content.save().getPk(); } finally { FxContext.get().stopRunAsSystem(); } try { assignMatrix(0, typeACL); assignMatrix(0, editACL); try { getContentEngine().load(pk); fail("User without groups should not be able to load the content."); } catch (FxNoAccessException e) { // pass } assertSearchReturnsPK(pk, 0); assignGroup(1); // should be able to: read, edit // read FxContent content = getContentEngine().load(pk); assertSearchReturnsPK(pk, 1); // update content.setValue("/p1", "A value"); content.save(); try { getContentEngine().remove(pk); fail("User from group 1 should not be able to delete the content."); } catch (FxNoAccessException e) { // pass } assignGroup(2); content = getContentEngine().load(pk); assertSearchReturnsPK(pk, 1); try { content.setValue("/p1", "Another value"); content.save(); fail("User from group 2 should not be able to edit the content."); } catch (FxNoAccessException e) { // pass } // removing should work getContentEngine().remove(pk); pk = null; } finally { FxContext.get().runAsSystem(); try { if (pk != null) { getContentEngine().remove(pk); } getAclEngine().remove(acl2); getAclEngine().remove(acl1); } finally { FxContext.get().stopRunAsSystem(); } } } private void assertSearchReturnsPK(FxPK pk, int expectedRows) throws FxApplicationException { assertEquals(EJBLookup.getSearchEngine().search("SELECT @pk WHERE id=" + pk.getId()).getRowCount(), expectedRows, "Expected " + expectedRows + " result rows."); } @Test public void defaultInstanceACLTest() throws FxApplicationException { FxContext.get().runAsSystem(); try { TypeEngine te = EJBLookup.getTypeEngine(); FxType ct = CacheAdmin.getEnvironment().getType(FxType.CONTACTDATA); //check default settings assertTrue(ct.hasDefaultInstanceACL()); assertEquals(ct.getDefaultInstanceACL().getId(), ACL.ACL_CONTACTDATA); //remove default acl te.save(ct.asEditable().setDefaultInstanceACL(null)); ct = CacheAdmin.getEnvironment().getType(FxType.CONTACTDATA); assertFalse(ct.hasDefaultInstanceACL()); //set to default instance ACL te.save(ct.asEditable() .setDefaultInstanceACL(CacheAdmin.getEnvironment().getDefaultACL(ACLCategory.INSTANCE))); ct = CacheAdmin.getEnvironment().getType(FxType.CONTACTDATA); assertTrue(ct.hasDefaultInstanceACL()); assertEquals(ct.getDefaultInstanceACL().getId(), ACLCategory.INSTANCE.getDefaultId()); assertEquals((long) getContentEngine().initialize(FxType.CONTACTDATA).getAclIds().get(0), ACLCategory.INSTANCE.getDefaultId()); //set back to default settings te.save(ct.asEditable().setDefaultInstanceACL(CacheAdmin.getEnvironment().getACL(ACL.ACL_CONTACTDATA))); ct = CacheAdmin.getEnvironment().getType(FxType.CONTACTDATA); assertTrue(ct.hasDefaultInstanceACL()); assertEquals(ct.getDefaultInstanceACL().getId(), ACL.ACL_CONTACTDATA); assertEquals((long) getContentEngine().initialize(FxType.CONTACTDATA).getAclIds().get(0), ACL.ACL_CONTACTDATA); } finally { FxContext.get().stopRunAsSystem(); } } }