Skip to content

Commit

Permalink
(Approximate) fix for MID-3815: Indirect relation=manager assignment …
Browse files Browse the repository at this point in the history
…of Authorization (MP only) role
  • Loading branch information
mederly committed Mar 24, 2017
1 parent afb4883 commit 89648de
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 9 deletions.
Expand Up @@ -639,8 +639,8 @@ private void evaluateSegmentTarget(AssignmentPathSegmentImpl segment, PlusMinusZ
evaluateAssignment(segment, mode, isValid, ctx, targetType, relation, roleAssignment);
}

boolean matchesOrder = AssignmentPathSegmentImpl.computeMatchingOrder(segment.getEvaluationOrder(), 1, Collections.emptyList());
if (matchesOrder && targetType instanceof AbstractRoleType && isNonNegative(mode)) {
//boolean matchesOrder = AssignmentPathSegmentImpl.computeMatchingOrder(segment.getEvaluationOrder(), 1, Collections.emptyList());
if (segment.isMatchingOrder() && targetType instanceof AbstractRoleType && isNonNegative(mode)) {
for (AuthorizationType authorizationType: ((AbstractRoleType)targetType).getAuthorization()) {
Authorization authorization = createAuthorization(authorizationType, targetType.toString());
if (!ctx.evalAssignment.getAuthorizations().contains(authorization)) {
Expand Down Expand Up @@ -755,11 +755,14 @@ private void evaluateInducement(AssignmentPathSegmentImpl segment, PlusMinusZero
nextEvaluationOrder = EvaluationOrderImpl.UNDEFINED;
nextEvaluationOrderForTarget = EvaluationOrderImpl.UNDEFINED;
}
} else {
} else if (inducement.getOrderConstraint().isEmpty()) {
// i.e. order is null or 1
nextEvaluationOrder = segment.getEvaluationOrder();
nextEvaluationOrderForTarget = segment.getEvaluationOrderForTarget();
} else {
nextEvaluationOrder = EvaluationOrderImpl.UNDEFINED;
nextEvaluationOrderForTarget = EvaluationOrderImpl.UNDEFINED;
}
// TODO undefined if intervals
nextSegment.setEvaluationOrder(nextEvaluationOrder, nextIsMatchingOrder);
nextSegment.setEvaluationOrderForTarget(nextEvaluationOrderForTarget, nextIsMatchingOrderForTarget);

Expand Down
Expand Up @@ -94,7 +94,7 @@ public class AssignmentPathSegmentImpl implements AssignmentPathSegment {
* it with the order (or, more generally, order constraints) of the inducement. If they match, we say that inducement
* has matching order.
*
* As for #2: It is not usual that inducements have targets with another assignments, i.e. that evaluation continues
* As for #2: It is not usual that inducements have targets (roles) with another assignments, i.e. that evaluation continues
* after inducement segments. But it definitely could happen. We can look at it this way: inducement is something like
* a "shortcut" that creates an assignment where no assignment was before. E.g. if we have R1 -A-> MR1 -I-> MR2,
* the "newly created" assignment is R1 -A-> MR2. I.e. as if the " -A-> MR1 -I-> " part was just replaced by " -A-> ".
Expand All @@ -106,12 +106,42 @@ public class AssignmentPathSegmentImpl implements AssignmentPathSegment {
* TODO think this through, perhaps based on concrete examples
*
* It is almost certain that for some inducements we would not be able to determine the resulting order.
* Such problematic inducements are those that do not have strict order, but an interval of orders instead.
* Such problematic inducements are those that do not have strict (scalar) order constraint, but something
* more complex, e.g. interval of orders.
*
* Until no better algorithm is devised, we will do an approximation: when "traditional" inducement order is given,
* the we will compute the resulting order as "previous - (N-1)", where N is the order of the inducement
* (unspecified means 1). But beware, we will not manipulate evaluation order parts that are specific to relations.
* So, it is not safe to combine "higher-order inducements with targets" with non-scalar order constraints.
* (unspecified means 1). But beware, we will not decrease evaluation order for non-default relations!
* Also, if the traditional inducement order is not given, but orderConstraints are present instead, we will
* simply stop evaluation of further path segments altogether.
*
* So, it is not supported to combine inducements with complex (non-scalar) order constraints with further
* targets (assignments/inducements). Only membership, authorizations and GUI config from such inducement targets
* will be collected. See test500/test510 in TestAssignmentProcessor2.
*
* Unfortunately, this is by no means a rare case. It can easily occur when org structures are used.
* As depicted in that test, imagine this:
*
* Org1 -----I----+ Org2 -----I----+
* ^ | (orderConstraints 1..N) ^ | (orderConstraints: manager: 1)
* | | | |
* | V | V
* Org11 Admin Org21 Admin
* ^ ^
* | (manager)
* | |
* jack jack
*
* So, we are in trouble when we try to attach an inducement to a organization hierarchy top; to be applied to
* users that are part of the organizational structure (at any level). The reason is that the inducement has
* to have non-scalar constraint.
*
* TODO think this through.
*
* Maybe something like "continue with specified evaluation order" could be provided in OrgX->Admin inducement.
* But this would be quite complicated.
*
* ----
*
* Because evaluation order can "increase" and "decrease", it is possible that it goes to zero or below, and then
* increase back to positive numbers. Is that OK? Imagine this:
Expand Down
Expand Up @@ -99,6 +99,7 @@ public class TestAssignmentProcessor2 extends AbstractLensTest {
private static final boolean FIRST_PART = true;
private static final boolean SECOND_PART = true;
private static final boolean THIRD_PART = true;
private static final boolean FOURTH_PART = true;

private static final File RESOURCE_DUMMY_EMPTY_FILE = new File(TEST_DIR, "resource-dummy-empty.xml");
private static final String RESOURCE_DUMMY_EMPTY_OID = "10000000-0000-0000-0000-00000000EEE4";
Expand All @@ -122,13 +123,19 @@ public class TestAssignmentProcessor2 extends AbstractLensTest {
private RoleType rolePirate, roleSailor, roleMan, roleWoman, roleHuman;
private RoleType metaroleCrewMember, metarolePerson;

// fourth part
private OrgType org1, org11, org2, org21;
private RoleType roleAdmin;

private List<ObjectType> objects;

private static final String ROLE_R1_OID = getRoleOid("R1");
private static final String ROLE_R7_OID = getRoleOid("R7");
private static final String ROLE_MR1_OID = getRoleOid("MR1");
private static final String ROLE_PIRATE_OID = getRoleOid("Pirate");
private static final String ROLE_MAN_OID = getRoleOid("Man");
private static final String ORG11_OID = getRoleOid("org11");
private static final String ORG21_OID = getRoleOid("org21");

@Override
public void initSystem(Task initTask, OperationResult initResult) throws Exception {
Expand Down Expand Up @@ -1399,6 +1406,111 @@ public static void finishCallback(String desc) {
}
}

/**
* Testing non-scalar constraints (MID-3815)
*
* Org1 -----I----+ Org2 -----I----+
* ^ | (orderConstraints 1..N) ^ | (orderConstraints: manager: 1)
* | | | |
* | V | V
* Org11 Admin Org21 Admin
* ^ ^
* | (manager)
* | |
* jack jack
*
* Authorizations and GUI configuration from role Admin should be given to jack.
*/

@Test(enabled = FOURTH_PART)
public void test500AssignJackOrg11() throws Exception {
final String TEST_NAME = "test500AssignJackOrg11";
TestUtil.displayTestTile(this, TEST_NAME);

// GIVEN
Task task = taskManager.createTaskInstance(TestAssignmentProcessor.class.getName() + "." + TEST_NAME);
OperationResult result = task.getResult();

createObjectsInFourthPart(false, task, result, null);

LensContext<UserType> context = createContextForAssignment(UserType.class, USER_JACK_OID, OrgType.class, ORG11_OID, null, null, result);

// WHEN
assignmentProcessor.processAssignmentsProjections(context, clock.currentTimeXMLGregorianCalendar(), task, result);

// THEN
display("Output context", context);
display("Evaluated assignment triple", context.getEvaluatedAssignmentTriple());

result.computeStatus();
assertSuccess("Assignment processor failed (result)", result);

Collection<EvaluatedAssignmentImpl<UserType>> evaluatedAssignments = assertAssignmentTripleSetSize(context, 0, 1, 0);
EvaluatedAssignmentImpl<UserType> evaluatedAssignment = evaluatedAssignments.iterator().next();
assertEquals("Wrong evaluatedAssignment.isValid", true, evaluatedAssignment.isValid());

assertTargets(evaluatedAssignment, true, "org11 Admin", null, null, null, null, null);
assertTargets(evaluatedAssignment, false, "org1", null, null, null, null, null);
assertMembershipRef(evaluatedAssignment, "org11 Admin");
assertOrgRef(evaluatedAssignment, "org11");
assertDelegation(evaluatedAssignment, "");

String expectedItems = "org11-1 org1-2";
assertConstructions(evaluatedAssignment, expectedItems, null, null, null, null, null);
assertFocusMappings(evaluatedAssignment, expectedItems);
assertFocusPolicyRules(evaluatedAssignment, expectedItems);

assertTargetPolicyRules(evaluatedAssignment,
"org11-0 org1-1",
"");
assertAuthorizations(evaluatedAssignment, "org11 Admin");
assertGuiConfig(evaluatedAssignment, "org11 Admin");
}

@Test(enabled = FOURTH_PART)
public void test510AssignJackOrg21() throws Exception {
final String TEST_NAME = "test510AssignJackOrg21";
TestUtil.displayTestTile(this, TEST_NAME);

// GIVEN
Task task = taskManager.createTaskInstance(TestAssignmentProcessor.class.getName() + "." + TEST_NAME);
OperationResult result = task.getResult();

LensContext<UserType> context = createContextForAssignment(UserType.class, USER_JACK_OID, OrgType.class, ORG21_OID,
new QName("manager"), null, result); // intentionally unqualified

// WHEN
assignmentProcessor.processAssignmentsProjections(context, clock.currentTimeXMLGregorianCalendar(), task, result);

// THEN
display("Output context", context);
display("Evaluated assignment triple", context.getEvaluatedAssignmentTriple());

result.computeStatus();
assertSuccess("Assignment processor failed (result)", result);

Collection<EvaluatedAssignmentImpl<UserType>> evaluatedAssignments = assertAssignmentTripleSetSize(context, 0, 1, 0);
EvaluatedAssignmentImpl<UserType> evaluatedAssignment = evaluatedAssignments.iterator().next();
assertEquals("Wrong evaluatedAssignment.isValid", true, evaluatedAssignment.isValid());

assertTargets(evaluatedAssignment, true, "org21 Admin", null, null, null, null, null);
assertTargets(evaluatedAssignment, false, "org2", null, null, null, null, null);
assertMembershipRef(evaluatedAssignment, "org21 Admin");
assertOrgRef(evaluatedAssignment, "org21");
assertDelegation(evaluatedAssignment, "");

String expectedItems = "org21-1 org2-2";
assertConstructions(evaluatedAssignment, expectedItems, null, null, null, null, null);
assertFocusMappings(evaluatedAssignment, expectedItems);
assertFocusPolicyRules(evaluatedAssignment, expectedItems);

assertTargetPolicyRules(evaluatedAssignment,
"org21-0 org2-1",
"");
assertAuthorizations(evaluatedAssignment, "org21 Admin");
assertGuiConfig(evaluatedAssignment, "org21 Admin");
}

//region ============================================================= helper methods (preparing scenarios)

private void createObjectsInFirstPart(boolean deleteFirst, Task task, OperationResult result, Runnable adjustment) throws Exception {
Expand Down Expand Up @@ -1478,6 +1590,36 @@ private void createObjectsInThirdPart(boolean deleteFirst, Task task, OperationR
createObjects(deleteFirst, task, result, adjustment);
}

private void createObjectsInFourthPart(boolean deleteFirst, Task task, OperationResult result, Runnable adjustment) throws Exception {
org1 = createOrg("org1");
org11 = createOrg("org11");
org2 = createOrg("org2");
org21 = createOrg("org21");
roleAdmin = createRole("Admin");

assign(org11, org1);
assign(org21, org2);
// org1->roleAdmin
AssignmentType inducement = ObjectTypeUtil.createAssignmentTo(roleAdmin.asPrismObject())
.beginOrderConstraint()
.orderMin("1")
.orderMax("unbounded")
.end();
org1.getInducement().add(inducement);

// org2->roleAdmin
AssignmentType inducement2 = ObjectTypeUtil.createAssignmentTo(roleAdmin.asPrismObject())
.beginOrderConstraint()
.order(1)
.relation(SchemaConstants.ORG_MANAGER)
.end();
org2.getInducement().add(inducement2);

objects = new ArrayList<>(Arrays.asList(roleAdmin, org1, org11, org2, org21));

createObjects(deleteFirst, task, result, adjustment);
}

private void createCustomConstruction(RoleType role, String name, int order) {
ConstructionType c = new ConstructionType(prismContext);
c.setDescription(name);
Expand Down Expand Up @@ -1597,7 +1739,7 @@ private void induce(AbstractRoleType source, AbstractRoleType target, int induce
source.getInducement().add(inducement);
}

private void assign(RoleType source, RoleType target) {
private void assign(AbstractRoleType source, AbstractRoleType target) {
AssignmentType assignment = ObjectTypeUtil.createAssignmentTo(target.asPrismObject());
source.getAssignment().add(assignment);
}
Expand Down

0 comments on commit 89648de

Please sign in to comment.