Skip to content

Commit

Permalink
Support nested "item value" authorizations
Browse files Browse the repository at this point in the history
Now we can specify nested "item value" authorizations - for example,
we can restrict work items in certification cases, which are themselves
restricted in certification campaign objects. We can also declare
inner "item" and "exceptItem" paths for specific item values.

Experimental implementation of "filter" value selection clause was
added as well.

Work in progress. Still no searching or other operations,
only "getObject" evaluation.
  • Loading branch information
mederly committed May 13, 2023
1 parent cffacf5 commit 30e5108
Show file tree
Hide file tree
Showing 29 changed files with 1,625 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ public abstract class AbstractSecurityTest extends AbstractInitializedModelInteg
protected static final TestObject<RoleType> ROLE_CASES_ASSIGNEE_SELF = TestObject.file(TEST_DIR, "role-cases-assignee-self.xml", "541ad3fc-1ae7-4412-a205-47093a78f0cf");
protected static final TestObject<RoleType> ROLE_CASES_OBJECT_SELF = TestObject.file(TEST_DIR, "role-cases-object-self.xml", "96bbb1be-cf8c-4e9c-a994-ec0fbfcadb1d");
protected static final TestObject<RoleType> ROLE_CASES_REQUESTOR_SELF = TestObject.file(TEST_DIR, "role-cases-requestor-self.xml", "d8a114e1-6f55-4380-876b-87071dbed1b7");
protected static final TestObject<RoleType> ROLE_CASE_WORK_ITEMS_ASSIGNEE_SELF_READ = TestObject.file(TEST_DIR, "role-case-work-items-assignee-self-read.xml", "efa5620b-0cf1-492e-8aab-9de3358bb525");
protected static final TestObject<RoleType> ROLE_OBJECT_FILTER_MODIFY_CARIBBEAN = TestObject.file(TEST_DIR, "role-filter-object-modify-caribbean.xml", "00000000-0000-0000-0000-00000000aa04");
protected static final TestObject<RoleType> ROLE_PROP_READ_ALL_MODIFY_SOME = TestObject.file(TEST_DIR, "role-prop-read-all-modify-some.xml", "00000000-0000-0000-0000-00000000aa05");
protected static final TestObject<RoleType> ROLE_PROP_READ_ALL_MODIFY_SOME_USER = TestObject.file(TEST_DIR, "role-prop-read-all-modify-some-user.xml", "00000000-0000-0000-0000-00000000ae05");
Expand Down Expand Up @@ -182,7 +181,9 @@ public abstract class AbstractSecurityTest extends AbstractInitializedModelInteg
protected static final String TASK_T5_OID = "a507e1c8-30e4-11e7-a739-538d921aa79e";
protected static final String TASK_T6_OID = "a522b610-30e4-11e7-ab1c-6f834b9ae963";

protected static final File CAMPAIGNS_FILE = new File(TEST_DIR, "campaigns.xml");
protected static final TestObject<AccessCertificationCampaignType> CAMPAIGN1 = TestObject.file(TEST_DIR, "access-certification-campaign-1.xml", "f2122c2f-d61f-4176-a35d-132a9f575a70");
protected static final TestObject<AccessCertificationCampaignType> CAMPAIGN2 = TestObject.file(TEST_DIR, "access-certification-campaign-2.xml", "8c0027d6-9074-4ab0-bb60-03c29c3e8130");
protected static final TestObject<AccessCertificationCampaignType> CAMPAIGN3 = TestObject.file(TEST_DIR, "access-certification-campaign-3.xml", "cb88d128-20f9-450f-88f3-889c15f88a62");

protected static final TestObject<CaseType> CASE1 = TestObject.file(TEST_DIR, "case-1.xml", "99cf4e9f-fced-4f09-a302-57ad3ad6c0c1");
protected static final TestObject<CaseType> CASE2 = TestObject.file(TEST_DIR, "case-2.xml", "13326d91-9308-499f-9ea7-a4d6daaad437");
Expand All @@ -195,7 +196,7 @@ public abstract class AbstractSecurityTest extends AbstractInitializedModelInteg
protected static final XMLGregorianCalendar JACK_VALID_TO_LONG_AHEAD = XmlTypeConverter.createXMLGregorianCalendar(10000000000000L);

protected static final int NUMBER_OF_ALL_USERS = 11;
protected static final int NUMBER_OF_IMPORTED_ROLES = 76;
protected static final int NUMBER_OF_IMPORTED_ROLES = 75;
protected static final int NUMBER_OF_ALL_ORGS = 11;

protected String userRumRogersOid;
Expand All @@ -205,12 +206,15 @@ public abstract class AbstractSecurityTest extends AbstractInitializedModelInteg
public void initSystem(Task initTask, OperationResult initResult) throws Exception {
super.initSystem(initTask, initResult);

repoAddObjectsFromFile(CAMPAIGNS_FILE, initResult);
repoAdd(CASE1, initResult);
repoAdd(CASE2, initResult);
repoAdd(CASE3, initResult);
repoAdd(CASE4, initResult);

repoAdd(CAMPAIGN1, initResult);
repoAdd(CAMPAIGN2, initResult);
repoAdd(CAMPAIGN3, initResult);

repoAdd(ARCHETYPE_BUSINESS_ROLE, initResult);
repoAdd(ARCHETYPE_APPLICATION_ROLE, initResult);

Expand All @@ -226,7 +230,6 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti
repoAdd(ROLE_CASES_ASSIGNEE_SELF, initResult);
repoAdd(ROLE_CASES_OBJECT_SELF, initResult);
repoAdd(ROLE_CASES_REQUESTOR_SELF, initResult);
repoAdd(ROLE_CASE_WORK_ITEMS_ASSIGNEE_SELF_READ, initResult);
repoAdd(ROLE_OBJECT_FILTER_MODIFY_CARIBBEAN, initResult);
repoAdd(ROLE_PROP_READ_ALL_MODIFY_SOME, initResult);
repoAdd(ROLE_PROP_READ_ALL_MODIFY_SOME_USER, initResult);
Expand Down Expand Up @@ -391,7 +394,7 @@ protected void assertSuperuserAccess(int readUserNum) throws Exception {
assertModifyAllow();
assertDeleteAllow();

assertSearch(AccessCertificationCampaignType.class, null, 2); // 2 campaigns there
assertSearch(AccessCertificationCampaignType.class, null, 3);
assertReadCertCasesAllow();
assertReadCasesAllow();
assertSearch(TaskType.class, null, getNumberOfTasks());
Expand Down Expand Up @@ -569,7 +572,7 @@ protected void assertReadCasesDeny() throws Exception {
}

protected void assertReadCertCasesAllow() throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException {
assertReadCertCases(3);
assertReadCertCases(11);
}

protected void assertReadCasesAllow() throws Exception {
Expand All @@ -588,6 +591,10 @@ protected void assertReadCases(String... expectedOids) throws Exception {
assertSearch(CaseType.class, null, expectedOids);
}

protected void assertReadCampaigns(String... expectedOids) throws Exception {
assertSearch(AccessCertificationCampaignType.class, null, expectedOids);
}

protected void assertReadDeny(int expectedNumAllUsers) throws Exception {
assertGetDeny(UserType.class, USER_JACK_OID);
assertGetDeny(UserType.class, USER_JACK_OID, SelectorOptions.createCollection(GetOperationOptions.createRaw()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
*/
package com.evolveum.midpoint.model.intest.security;

import com.evolveum.midpoint.test.TestObject;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
import org.testng.annotations.Test;

import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CaseType;

/**
* Tests the security functions related to sub-object structures, like:
Expand All @@ -28,16 +30,32 @@
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
public class TestSecurityItemValues extends AbstractSecurityTest {

private static final TestObject<RoleType> ROLE_CASE_WORK_ITEMS_ASSIGNEE_SELF_READ = TestObject.file(
TEST_DIR, "role-case-work-items-assignee-self-read.xml", "efa5620b-0cf1-492e-8aab-9de3358bb525");
private static final TestObject<RoleType> ROLE_CASE_WORK_ITEMS_EVENT_APPROVED_READ = TestObject.file(
TEST_DIR, "role-case-work-items-event-approved-read.xml", "6b2af0ae-36a6-4e90-8cff-1f2172566956");
private static final TestObject<RoleType> ROLE_ACC_CERT_CASE_WORK_ITEMS_ASSIGNEE_SELF_READ = TestObject.file(
TEST_DIR, "role-acc-cert-case-work-items-assignee-self-read.xml", "7090f927-d393-4dc6-aefb-d3c83408978b");
private static final TestObject<RoleType> ROLE_ACC_CERT_CAMPAIGN_COMPLEX_READ = TestObject.file(
TEST_DIR, "role-acc-cert-campaign-complex-read.xml", "2ce049c4-fd83-44d5-b5eb-19b4a156c262");

@Override
public void initSystem(Task initTask, OperationResult initResult) throws Exception {
super.initSystem(initTask, initResult);

initTestObjects(initTask, initResult,
ROLE_CASE_WORK_ITEMS_ASSIGNEE_SELF_READ,
ROLE_CASE_WORK_ITEMS_EVENT_APPROVED_READ,
ROLE_ACC_CERT_CASE_WORK_ITEMS_ASSIGNEE_SELF_READ,
ROLE_ACC_CERT_CAMPAIGN_COMPLEX_READ);
}

@Test
public void test100CaseWorkItemsAssigneeSelfRead() throws Exception {
given();
cleanupAutzTest(USER_JACK_OID);
assignRole(USER_JACK_OID, ROLE_CASE_WORK_ITEMS_ASSIGNEE_SELF_READ.oid);
assignRole(USER_JACK_OID, ROLE_CASE_WORK_ITEMS_EVENT_APPROVED_READ.oid);

when();
login(USER_JACK_USERNAME);
Expand All @@ -46,25 +64,187 @@ public void test100CaseWorkItemsAssigneeSelfRead() throws Exception {
assertReadCases(CASE1.oid, CASE2.oid, CASE3.oid, CASE4.oid);

and("but not all their work items");
assertGetWorkItems(CASE1.oid).assertSize(0); // none assigned to jack
assertGetWorkItems(CASE2.oid).assertSize(0); // none assigned to jack
assertGetWorkItems(CASE3.oid)
.single()
.assertAssignees(USER_JACK_OID);
assertGetWorkItems(CASE4.oid)
.single()
.assertAssignees(USER_JACK_OID);
// @formatter:off
assertCase(CASE1.oid, "after")
.workItems()
.assertNone() // none assigned to jack
.end()
.events()
.assertEvents(1); // only single is approved
assertCase(CASE2.oid, "after")
.workItems()
.assertNone() // none assigned to jack
.end()
.events()
.assertEvents(1); // only single is approved
assertCase(CASE3.oid, "after")
.workItems()
.single()
.assertAssignees(USER_JACK_OID)
.end()
.end()
.events()
.assertEvents(1); // only single is approved
assertCase(CASE4.oid, "after")
.workItems()
.single()
.assertAssignees(USER_JACK_OID)
.end()
.end()
.events()
.assertNone(); // none is approved
// @formatter:on

and("only allowed items are there");
assertCaseAfter(CASE1.oid)
.assertItems(CaseType.F_NAME);
.assertItems(CaseType.F_NAME, CaseType.F_EVENT);
assertCaseAfter(CASE2.oid)
.assertItems(CaseType.F_NAME);
.assertItems(CaseType.F_NAME, CaseType.F_EVENT);
assertCaseAfter(CASE3.oid)
.assertItems(CaseType.F_NAME, CaseType.F_WORK_ITEM);
.assertItems(CaseType.F_NAME, CaseType.F_WORK_ITEM, CaseType.F_EVENT);
assertCaseAfter(CASE4.oid)
.assertItems(CaseType.F_NAME, CaseType.F_WORK_ITEM);

// TODO continue
}

@Test
public void test110AccCertCaseWorkItemsAssigneeSelfRead() throws Exception {
given();
cleanupAutzTest(USER_JACK_OID);
assignRole(USER_JACK_OID, ROLE_ACC_CERT_CASE_WORK_ITEMS_ASSIGNEE_SELF_READ.oid);

when();
login(USER_JACK_USERNAME);

then("can see all cert campaigns (because of 'all cases' object selector)");
assertReadCampaigns(CAMPAIGN1.oid, CAMPAIGN2.oid, CAMPAIGN3.oid);

and("but only allowed items are visible");
// @formatter:off
assertCampaignFullAfter(CAMPAIGN3.oid)
.assertItems(AccessCertificationCampaignType.F_NAME, AccessCertificationCampaignType.F_CASE)
.container(AccessCertificationCampaignType.F_CASE)
.valueWithId(6)
.assertItemsExactly(AccessCertificationCaseType.F_WORK_ITEM)
.containerSingle(AccessCertificationCaseType.F_WORK_ITEM)
.assertId(1L)
.assertItemsExactly(
AccessCertificationWorkItemType.F_STAGE_NUMBER,
AccessCertificationWorkItemType.F_ASSIGNEE_REF)
.end()
.end()
.valueWithId(7)
.assertItemsExactly(AccessCertificationCaseType.F_WORK_ITEM)
.containerSingle(AccessCertificationCaseType.F_WORK_ITEM)
.assertId(2L)
.assertItemsExactly(
AccessCertificationWorkItemType.F_NAME,
AccessCertificationWorkItemType.F_STAGE_NUMBER,
AccessCertificationWorkItemType.F_ASSIGNEE_REF)
.end()
.end()
.assertSize(2); // no others!
// @formatter:on
}

/**
* Authorizations:
*
* - `campaign-name-and-case-outcome` - allows `name` and `case/outcome` for all cases i.e. 1, 2, 3, 4, 5, 6, 7, 8
* - `campaign-case-iteration-for-object-ann` - allows `case/iteration` for cases 5, 6, 7, 8
* - `no-campaign-case-outcome-and-iteration-for-target-approver` - denies `case/outcome` and `case/iteration` for case 6
* - `no-campaign-case-for-object-administrator` - denies the whole case 1
* - `campaign-work-items-assigned-to-administrator` - allows `case/workItem/assigneeRef` for work items
* 1.1, 2.1, 3.1, 4.1, 5.1, 6.2, 7.1, 8.1; not apples to work items 6.1, 7.2
* - `campaign-extra-work-item` - allows `case/workItem/*` (except for `stageNumber`) for work item 8.1
*/
@Test
public void test120AccCertCampaignComplexRead() throws Exception {
given();
cleanupAutzTest(USER_JACK_OID);
assignRole(USER_JACK_OID, ROLE_ACC_CERT_CAMPAIGN_COMPLEX_READ.oid);

when();
login(USER_JACK_USERNAME);

then("can see all cert campaigns (because of 'all cases' object selector)");
assertReadCampaigns(CAMPAIGN1.oid, CAMPAIGN2.oid, CAMPAIGN3.oid);

and("but only allowed items are visible");
// @formatter:off
assertCampaignFullAfter(CAMPAIGN3.oid)
.assertItems(AccessCertificationCampaignType.F_NAME, AccessCertificationCampaignType.F_CASE)
.container(AccessCertificationCampaignType.F_CASE)
.assertNoValueWithId(1L) // explicitly denied by "no-campaign-case-for-object-administrator"
.valueWithId(2L)
// allowed by "campaign-name-and-case-outcome", "campaign-work-items-assigned-to-administrator"
.assertItemsExactly(AccessCertificationCaseType.F_WORK_ITEM, AccessCertificationCaseType.F_OUTCOME)
.containerSingle(AccessCertificationCaseType.F_WORK_ITEM)
.assertId(1L)
.assertItemsExactly(AccessCertificationWorkItemType.F_ASSIGNEE_REF)
.end()
.end()
.valueWithId(3) // the same as #2
.assertItemsExactly(AccessCertificationCaseType.F_WORK_ITEM, AccessCertificationCaseType.F_OUTCOME)
.containerSingle(AccessCertificationCaseType.F_WORK_ITEM)
.assertId(1L)
.assertItemsExactly(AccessCertificationWorkItemType.F_ASSIGNEE_REF)
.end()
.end()
.valueWithId(4) // the same as #2
.assertItemsExactly(AccessCertificationCaseType.F_WORK_ITEM, AccessCertificationCaseType.F_OUTCOME)
.containerSingle(AccessCertificationCaseType.F_WORK_ITEM)
.assertId(1L)
.assertItemsExactly(AccessCertificationWorkItemType.F_ASSIGNEE_REF)
.end()
.end()
.valueWithId(5)
// allowed by "campaign-name-and-case-outcome", "campaign-work-items-assigned-to-administrator"
// and "campaign-case-iteration-for-object-ann"
.assertItemsExactly(
AccessCertificationCaseType.F_WORK_ITEM,
AccessCertificationCaseType.F_OUTCOME,
AccessCertificationCaseType.F_ITERATION)
.containerSingle(AccessCertificationCaseType.F_WORK_ITEM)
.assertId(1L)
.assertItemsExactly(AccessCertificationWorkItemType.F_ASSIGNEE_REF)
.end()
.end()
.valueWithId(6)
// as #5 but outcome and iteration denied by "no-campaign-case-outcome-and-iteration-for-target-approver"
.assertItemsExactly(AccessCertificationCaseType.F_WORK_ITEM)
.containerSingle(AccessCertificationCaseType.F_WORK_ITEM)
.assertId(2L)
.assertItemsExactly(AccessCertificationWorkItemType.F_ASSIGNEE_REF)
.end()
.end()
.valueWithId(7)
// as #5
.assertItemsExactly(
AccessCertificationCaseType.F_WORK_ITEM,
AccessCertificationCaseType.F_OUTCOME,
AccessCertificationCaseType.F_ITERATION)
.containerSingle(AccessCertificationCaseType.F_WORK_ITEM)
.assertId(1L)
.assertItemsExactly(AccessCertificationWorkItemType.F_ASSIGNEE_REF)
.end()
.end()
.valueWithId(8)
// as #5 but the work item is visible almost fully
.assertItemsExactly(
AccessCertificationCaseType.F_WORK_ITEM,
AccessCertificationCaseType.F_OUTCOME,
AccessCertificationCaseType.F_ITERATION)
.containerSingle(AccessCertificationCaseType.F_WORK_ITEM)
.assertId(1L)
.assertItemsExactly(
AccessCertificationWorkItemType.F_NAME,
AccessCertificationWorkItemType.F_ORIGINAL_ASSIGNEE_REF,
AccessCertificationWorkItemType.F_ASSIGNEE_REF,
AccessCertificationWorkItemType.F_ITERATION)
.end()
.end();
// @formatter:on
}
}

0 comments on commit 30e5108

Please sign in to comment.