diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReferenceValue.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReferenceValue.java index 19d269bdccc..a2666b03acb 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReferenceValue.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReferenceValue.java @@ -363,10 +363,10 @@ public boolean isEmpty() { } /** - * Returns a version of this value that is cannonical, that means it has the minimal form. + * Returns a version of this value that is canonical, that means it has the minimal form. * E.g. it will have only OID and no object. */ - public PrismReferenceValue toCannonical() { + public PrismReferenceValue toCanonical() { PrismReferenceValue can = new PrismReferenceValue(); can.setOid(getOid()); // do NOT copy object @@ -597,15 +597,19 @@ public String debugDump(int indent, boolean expandObject) { @Override public PrismReferenceValue clone() { + return clone(true); + } + + public PrismReferenceValue clone(boolean copyFullObject) { PrismReferenceValue clone = new PrismReferenceValue(getOid(), getOriginType(), getOriginObject()); - copyValues(clone); + copyValues(clone, copyFullObject); return clone; } - protected void copyValues(PrismReferenceValue clone) { + protected void copyValues(PrismReferenceValue clone, boolean copyFullObject) { super.copyValues(clone); clone.targetType = this.targetType; - if (this.object != null) { + if (this.object != null && copyFullObject) { clone.object = this.object.clone(); } clone.description = this.description; diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/EvaluatedAssignmentTarget.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/EvaluatedAssignmentTarget.java index d48da5818f4..d4914e4d60a 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/EvaluatedAssignmentTarget.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/EvaluatedAssignmentTarget.java @@ -47,4 +47,6 @@ public interface EvaluatedAssignmentTarget extends DebugDumpable { AssignmentType getAssignment(); AssignmentPath getAssignmentPath(); + + boolean isValid(); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java index 5c74eb79a75..41e320575be 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java @@ -326,21 +326,19 @@ private boolean evaluateSegmentContent(AssignmentPathSegm // Here we ignore "reallyValid". It is OK, because reallyValid can be false here only when // evaluating direct assignments; and invalid ones are marked as such via EvaluatedAssignment.isValid. // (This is currently ignored by downstream processing, but that's another story. Will be fixed soon.) - // --- - // But we also ignore "mode". This is because focus mappings are not categorized into PLUS/MINUS/ZERO sets. - // They are simply evaluated as they are: skipped only if both condOld and condNew is false. - // This is less sophisticated than constructions, but for the time being it is perhaps OK. - // TODO But shouldn't we skip focus mapping with mode==null? And with mode=MINUS? - evaluateFocusMappings(segment, ctx); + if (isNonNegative(mode)) { + evaluateFocusMappings(segment, ctx); + } } if (assignmentType.getPolicyRule() != null && !loginMode) { // We can ignore "reallyValid" for the same reason as for focus mappings. - // TODO but what if mode is null or MINUS? - if (segment.isMatchingOrder()) { - collectPolicyRule(true, segment, ctx); - } - if (segment.isMatchingOrderPlusOne()) { - collectPolicyRule(false, segment, ctx); + if (isNonNegative(mode)) { + if (segment.isMatchingOrder()) { + collectPolicyRule(true, segment, ctx); + } + if (segment.isMatchingOrderPlusOne()) { + collectPolicyRule(false, segment, ctx); + } } } if (assignmentType.getTarget() != null || assignmentType.getTargetRef() != null) { @@ -422,6 +420,9 @@ private void collectConstruction(AssignmentPathSegmentImpl segment, PlusMinusZer construction.setValid(isValid); // Do not evaluate the construction here. We will do it in the second pass. Just prepare everything to be evaluated. + if (mode == null) { + return; // null mode (i.e. plus + minus) means 'ignore the payload' + } switch (mode) { case PLUS: ctx.evalAssignment.addConstructionPlus(construction); @@ -625,15 +626,12 @@ private void evaluateSegmentTarget(AssignmentPathSegmentImpl segment, } } - EvaluatedAssignmentTargetImpl evalAssignmentTarget = new EvaluatedAssignmentTargetImpl(); - evalAssignmentTarget.setTarget(targetType.asPrismObject()); - evalAssignmentTarget.setEvaluateConstructions(segment.isMatchingOrder()); - evalAssignmentTarget.setAssignment(segment.getAssignment()); - evalAssignmentTarget.setDirectlyAssigned(ctx.assignmentPath.size() == 1); - evalAssignmentTarget.setAssignmentPath(ctx.assignmentPath.clone()); + EvaluatedAssignmentTargetImpl evalAssignmentTarget = new EvaluatedAssignmentTargetImpl( + targetType.asPrismObject(), segment.isMatchingOrder(), + ctx.assignmentPath.clone(), segment.getAssignment(), isValid); ctx.evalAssignment.addRole(evalAssignmentTarget, mode); - if (mode != PlusMinusZero.MINUS && segment.isProcessMembership()) { + if ((isNonNegative(mode)) && segment.isProcessMembership()) { PrismReferenceValue refVal = new PrismReferenceValue(); refVal.setObject(targetType.asPrismObject()); refVal.setTargetType(ObjectTypes.getObjectType(targetType.getClass()).getTypeQName()); @@ -769,9 +767,9 @@ private void evaluateSegmentTarget(AssignmentPathSegmentImpl segment, evaluateFromSegment(subAssignmentPathSegment, mode, ctx); } - if (evaluationOrder.getSummaryOrder() == 1 && targetType instanceof AbstractRoleType) { + if (evaluationOrder.getSummaryOrder() == 1 && targetType instanceof AbstractRoleType && isNonNegative(mode)) { - for(AuthorizationType authorizationType: ((AbstractRoleType)targetType).getAuthorization()) { + for (AuthorizationType authorizationType: ((AbstractRoleType)targetType).getAuthorization()) { Authorization authorization = createAuthorization(authorizationType, targetType.toString()); ctx.evalAssignment.addAuthorization(authorization); } @@ -788,6 +786,12 @@ private void evaluateSegmentTarget(AssignmentPathSegmentImpl segment, LOGGER.trace("Evaluating segment target DONE for {}", segment); } + private boolean isNonNegative(PlusMinusZero mode) { + // mode == null is also considered negative, because it is a combination of PLUS and MINUS; + // so the net result is that for both old and new state there exists an unsatisfied condition on the path. + return mode == PlusMinusZero.ZERO || mode == PlusMinusZero.PLUS; + } + private void checkRelationWithTarget(AssignmentPathSegmentImpl segment, FocusType targetType, QName relation) throws SchemaException { if (targetType instanceof AbstractRoleType) { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegmentImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegmentImpl.java index 7e8684022a7..019e4ba8499 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegmentImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegmentImpl.java @@ -413,6 +413,12 @@ public String toString() { if (assignmentType.getConstruction() != null) { sb.append("Constr '").append(assignmentType.getConstruction().getDescription()).append("' "); } + if (assignmentType.getFocusMappings() != null) { + sb.append("FMappings (").append(assignmentType.getFocusMappings().getMapping().size()).append(") "); + } + if (assignmentType.getPolicyRule() != null) { + sb.append("Rule '").append(assignmentType.getPolicyRule().getName()).append("' "); + } } ObjectReferenceType targetRef = assignmentType != null ? assignmentType.getTargetRef() : null; if (target != null || targetRef != null) { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignmentTargetImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignmentTargetImpl.java index d1dfde3c962..e222f7d9270 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignmentTargetImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignmentTargetImpl.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2015-2016 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,17 +15,13 @@ */ package com.evolveum.midpoint.model.impl.lens; -import java.util.ArrayList; -import java.util.Collection; - import com.evolveum.midpoint.model.api.context.EvaluatedAssignmentTarget; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.util.DebugUtil; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ExclusionPolicyConstraintType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.PolicyConstraintsType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; + +import java.util.ArrayList; +import java.util.Collection; /** * @author semancik @@ -33,29 +29,32 @@ */ public class EvaluatedAssignmentTargetImpl implements EvaluatedAssignmentTarget { - PrismObject target; - private boolean directlyAssigned; - private boolean evaluateConstructions; - private AssignmentPathImpl assignmentPath; // TODO reconsider (maybe we should store only some lightweight information here) - private AssignmentType assignment; + final PrismObject target; + private final boolean evaluateConstructions; + private final AssignmentPathImpl assignmentPath; // TODO reconsider (maybe we should store only some lightweight information here) + private final AssignmentType assignment; private Collection exclusions = null; + private final boolean isValid; + + EvaluatedAssignmentTargetImpl( + PrismObject target, boolean evaluateConstructions, + AssignmentPathImpl assignmentPath, AssignmentType assignment, + boolean isValid) { + this.target = target; + this.evaluateConstructions = evaluateConstructions; + this.assignmentPath = assignmentPath; + this.assignment = assignment; + this.isValid = isValid; + } @Override public PrismObject getTarget() { return target; } - public void setTarget(PrismObject target) { - this.target = target; - } - @Override public boolean isDirectlyAssigned() { - return directlyAssigned; - } - - public void setDirectlyAssigned(boolean directlyAssigned) { - this.directlyAssigned = directlyAssigned; + return assignmentPath.size() == 1; } @Override @@ -68,32 +67,25 @@ public boolean isEvaluateConstructions() { return evaluateConstructions; } - public void setEvaluateConstructions(boolean evaluateConstructions) { - this.evaluateConstructions = evaluateConstructions; - } - @Override public AssignmentType getAssignment() { return assignment; } - public void setAssignment(AssignmentType assignment) { - this.assignment = assignment; - } - @Override public AssignmentPathImpl getAssignmentPath() { return assignmentPath; } - public void setAssignmentPath(AssignmentPathImpl assignmentPath) { - this.assignmentPath = assignmentPath; - } - public String getOid() { return target.getOid(); } + @Override + public boolean isValid() { + return isValid; + } + public Collection getExclusions() { if (exclusions == null) { exclusions = new ArrayList<>(); @@ -132,8 +124,9 @@ public String debugDump(int indent) { DebugUtil.debugDumpWithLabel(sb, "Target", target, indent + 1); sb.append("\n"); DebugUtil.debugDumpWithLabel(sb, "Assignment", String.valueOf(assignment), indent + 1); + sb.append("\n"); + DebugUtil.debugDumpWithLabel(sb, "isValid", isValid, indent + 1); return sb.toString(); } - } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java index 8e77cb78681..8d377f9a0ee 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java @@ -50,7 +50,6 @@ import com.evolveum.midpoint.prism.PrismContainerDefinition; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.PrismPropertyValue; import com.evolveum.midpoint.prism.PrismReference; import com.evolveum.midpoint.prism.PrismReferenceDefinition; @@ -334,15 +333,15 @@ private void processAssignmentsProjectionsWithFocus(LensCo LOGGER.trace("ZERO construction pack: null"); } else { LOGGER.trace("ZERO construction pack (hasValidAssignment={}, hasStrongConstruction={})\n{}", - new Object[]{zeroConstructionPack.hasValidAssignment(), zeroConstructionPack.hasStrongConstruction(), - zeroConstructionPack.debugDump(1)}); + zeroConstructionPack.hasValidAssignment(), zeroConstructionPack.hasStrongConstruction(), + zeroConstructionPack.debugDump(1)); } if (plusConstructionPack == null) { LOGGER.trace("PLUS construction pack: null"); } else { LOGGER.trace("PLUS construction pack (hasValidAssignment={}, hasStrongConstruction={})\n{}", - new Object[]{plusConstructionPack.hasValidAssignment(), plusConstructionPack.hasStrongConstruction(), - plusConstructionPack.debugDump(1)}); + plusConstructionPack.hasValidAssignment(), plusConstructionPack.hasStrongConstruction(), + plusConstructionPack.debugDump(1)); } } @@ -705,14 +704,14 @@ private void collectToConstructionMapFromEvaluatedConstruc ResourceType resource = LensUtil.getResourceReadOnly(context, resourceOid, provisioningService, task, result); intent = LensUtil.refineProjectionIntent(kind, intent, resource, prismContext); ResourceShadowDiscriminator rat = new ResourceShadowDiscriminator(resourceOid, kind, intent); - ConstructionPack constructionPack = null; + ConstructionPack constructionPack; if (constructionMap.containsKey(rat)) { constructionPack = constructionMap.get(rat); } else { constructionPack = new ConstructionPack(); constructionMap.put(rat, constructionPack); } - constructionPack.add(new PrismPropertyValue(construction)); + constructionPack.add(new PrismPropertyValue<>(construction)); if (evaluatedAssignment.isValid()) { constructionPack.setHasValidAssignment(true); } @@ -852,7 +851,7 @@ private void propagateLegalDecisionToHigherOrders( } } - private void createAssignmentDelta(LensContext context, LensProjectionContext accountContext) throws SchemaException{ + private void createAssignmentDelta(LensContext context, LensProjectionContext accountContext) throws SchemaException{ Class focusClass = context.getFocusClass(); ContainerDelta assignmentDelta = ContainerDelta.createDelta(FocusType.F_ASSIGNMENT, focusClass, prismContext); AssignmentType assignment = new AssignmentType(); @@ -866,144 +865,28 @@ private void createAssignmentDelta(L } - public void processOrgAssignments(LensContext context, - OperationResult result) throws SchemaException { + public void processOrgAssignments(LensContext context, OperationResult result) throws SchemaException { + LensFocusContext focusContext = context.getFocusContext(); - DeltaSetTriple evaluatedAssignmentTriple = context.getEvaluatedAssignmentTriple(); - if (focusContext == null || evaluatedAssignmentTriple == null) { + if (focusContext == null) { return; } - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Starting processing org assignments into parentOrgRef delta(s); evaluatedAssignmentTriple is:\n{}", - evaluatedAssignmentTriple.debugDump()); - } - - Class focusClass = focusContext.getObjectTypeClass(); - PrismObjectDefinition userDef = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(focusClass); - PrismReferenceDefinition orgRefDef = userDef.findReferenceDefinition(FocusType.F_PARENT_ORG_REF); - ItemPath orgRefPath = new ItemPath(FocusType.F_PARENT_ORG_REF); + Collection shouldBeParentOrgRefs = new ArrayList<>(); - // check if parentOrgRef recon is needed - it is when something inside OrgType assignment has changed - boolean forceRecon = context.isReconcileFocus(); // this is directly influenced by Reconcile model execution option - if (!forceRecon) { - for (EvaluatedAssignmentImpl assignment : evaluatedAssignmentTriple.getAllValues()) { - if (assignment.isForceRecon() && - assignment.getAssignmentType() != null && - assignment.getAssignmentType().getTargetRef() != null && - OrgType.COMPLEX_TYPE.equals(assignment.getAssignmentType().getTargetRef().getType())) { - forceRecon = true; - break; + DeltaSetTriple evaluatedAssignmentTriple = context.getEvaluatedAssignmentTriple(); + if (evaluatedAssignmentTriple != null) { + for (EvaluatedAssignmentImpl evalAssignment: evaluatedAssignmentTriple.getNonNegativeValues()) { + if (evalAssignment.isValid()) { + addReferences(shouldBeParentOrgRefs, evalAssignment.getOrgRefVals()); } } } - // for zero and minus sets we check isForceRecon for all non-construction-related assignments (MID-2242) - // TODO why "non-construction-related" ones only? - if (!forceRecon) { - for (EvaluatedAssignmentImpl assignment: evaluatedAssignmentTriple.getNonPositiveValues()) { - if (assignment.isForceRecon() && assignment.getConstructions().isEmpty()) { - forceRecon = true; - break; - } - } - } - - if (!forceRecon) { // if no recon, we simply add/delete values as needed - - LOGGER.trace("No reconciliation requested, processing plus and minus sets"); - - // A list of values that are _not_ to be removed - these are all the values from zero set, - // as well as values from plus set. - // - // Contrary to existing standard delta merge algorithm (where add+delete means "keep the current state"), - // we ignore any delete of values that should be existing or added. - - Collection notToBeDeletedCanonical = new HashSet<>(); - for (EvaluatedAssignmentImpl assignment : evaluatedAssignmentTriple.getZeroSet()) { - Collection orgs = assignment.getOrgRefVals(); - for (PrismReferenceValue org : orgs) { - notToBeDeletedCanonical.add(org.toCannonical()); - } - } - - // Plus - for (EvaluatedAssignmentImpl assignment : evaluatedAssignmentTriple.getPlusSet()) { - Collection orgs = assignment.getOrgRefVals(); - for (PrismReferenceValue org : orgs) { - ItemDelta orgRefDelta = orgRefDef.createEmptyDelta(orgRefPath); - PrismReferenceValue orgCanonical = org.toCannonical(); - orgRefDelta.addValueToAdd(orgCanonical); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Created parentOrgRef delta:\n{}", orgRefDelta.debugDump()); - } - focusContext.swallowToProjectionWaveSecondaryDelta(orgRefDelta); - - notToBeDeletedCanonical.add(orgCanonical); - } - } - - // Minus (except for these that are also in zero set) - for (EvaluatedAssignmentImpl assignment : evaluatedAssignmentTriple.getMinusSet()) { - Collection orgs = assignment.getOrgRefVals(); - for (PrismReferenceValue org : orgs) { - ItemDelta orgRefDelta = orgRefDef.createEmptyDelta(orgRefPath); - PrismReferenceValue orgCanonical = org.toCannonical(); - if (notToBeDeletedCanonical.contains(orgCanonical)) { - LOGGER.trace("Not removing {} because it is in the zero or plus set", orgCanonical); - } else { - orgRefDelta.addValueToDelete(orgCanonical); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Created parentOrgRef delta:\n{}", orgRefDelta.debugDump()); - } - focusContext.swallowToProjectionWaveSecondaryDelta(orgRefDelta); - } - } - } - - } else { // if reconciliation is requested, we recreate parentOrgRef from scratch - - LOGGER.trace("Reconciliation requested, collecting all non-negative values"); - - Set valuesToReplace = new HashSet<>(); - - for (EvaluatedAssignmentImpl assignment : evaluatedAssignmentTriple.getNonNegativeValues()) { - Collection orgs = assignment.getOrgRefVals(); - for (PrismReferenceValue org : orgs) { - PrismReferenceValue canonical = org.toCannonical(); - valuesToReplace.add(canonical); // if valuesToReplace would be a list, we should check for duplicates! - } - } - PrismObject objectNew = focusContext.getObjectNew(); - if (parentOrgRefDiffers(objectNew, valuesToReplace)) { - ItemDelta orgRefDelta = orgRefDef.createEmptyDelta(orgRefPath); - orgRefDelta.setValuesToReplace(valuesToReplace); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Created parentOrgRef delta:\n{}", orgRefDelta.debugDump()); - } - focusContext.swallowToProjectionWaveSecondaryDelta(orgRefDelta); - } else { - LOGGER.trace("Computed parentOrgRef is the same as the value in objectNew -- skipping application of the delta"); - } - } - LOGGER.trace("Processing org assignments into parentOrgRef delta(s) done."); - } - private boolean parentOrgRefDiffers(PrismObject objectNew, Set valuesToReplace) { - if (objectNew == null) { - return true; // the result is probably irrelevant, as the object is going to be deleted - but it's safer not to skip parentOrgRef delta - } - PrismReference parentOrgRef = objectNew.findReference(ObjectType.F_PARENT_ORG_REF); - List existingValues; - if (parentOrgRef != null) { - existingValues = parentOrgRef.getValues(); - } else { - existingValues = new ArrayList<>(); - } - boolean equal = MiscUtil.unorderedCollectionEquals(existingValues, valuesToReplace); - return !equal; + setReferences(focusContext, ObjectType.F_PARENT_ORG_REF, shouldBeParentOrgRefs); } - public void checkForAssignmentConflicts(LensContext context, + public void checkForAssignmentConflicts(LensContext context, OperationResult result) throws PolicyViolationException { for(LensProjectionContext projectionContext: context.getProjectionContexts()) { if (AssignmentPolicyEnforcementType.NONE == projectionContext.getAssignmentPolicyEnforcementType()){ @@ -1078,13 +961,13 @@ public void removeIgnoredContexts(LensContext context) } private XMLGregorianCalendar collectFocusTripleFromMappings( - Collection> evaluatedAssignmnents, + Collection> evaluatedAssignments, Map>> outputTripleMap, PlusMinusZero plusMinusZero) throws SchemaException { XMLGregorianCalendar nextRecomputeTime = null; - for (EvaluatedAssignmentImpl ea: evaluatedAssignmnents) { + for (EvaluatedAssignmentImpl ea: evaluatedAssignments) { Collection> focusMappings = (Collection)ea.getFocusMappings(); for (Mapping mapping: focusMappings) { @@ -1124,13 +1007,13 @@ public void processMembershipAndDelegatedRefs(LensContext Collection shouldBeDelegatedRefs = new ArrayList<>(); DeltaSetTriple evaluatedAssignmentTriple = context.getEvaluatedAssignmentTriple(); - if (evaluatedAssignmentTriple == null) { - return; - } - - for (EvaluatedAssignmentImpl evalAssignment: evaluatedAssignmentTriple.getNonNegativeValues()) { - addReferences(shouldBeRoleRefs, evalAssignment.getMembershipRefVals()); - addReferences(shouldBeDelegatedRefs, evalAssignment.getDelegationRefVals()); + if (evaluatedAssignmentTriple != null) { + for (EvaluatedAssignmentImpl evalAssignment : evaluatedAssignmentTriple.getNonNegativeValues()) { + if (evalAssignment.isValid()) { + addReferences(shouldBeRoleRefs, evalAssignment.getMembershipRefVals()); + addReferences(shouldBeDelegatedRefs, evalAssignment.getDelegationRefVals()); + } + } } setReferences(focusContext, FocusType.F_ROLE_MEMBERSHIP_REF, shouldBeRoleRefs); @@ -1180,7 +1063,7 @@ private void addReferences(Collection extractedReferences, } } if (!found) { - PrismReferenceValue ref = reference.clone(); + PrismReferenceValue ref = reference.clone(false); // using copyObject=false instead of calling canonicalize() if (ref.getRelation() != null && QNameUtil.isUnqualified(ref.getRelation())) { ref.setRelation(new QName(SchemaConstants.NS_ORG, ref.getRelation().getLocalPart(), SchemaConstants.PREFIX_NS_ORG)); } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentProcessor2.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentProcessor2.java index dbe99739263..e82ab93bb00 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentProcessor2.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentProcessor2.java @@ -19,7 +19,9 @@ import com.evolveum.midpoint.model.api.context.EvaluatedPolicyRule; import com.evolveum.midpoint.model.impl.lens.projector.AssignmentProcessor; import com.evolveum.midpoint.prism.delta.PlusMinusZero; +import com.evolveum.midpoint.prism.delta.builder.DeltaBuilder; import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.schema.constants.ObjectTypes; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ActivationUtil; @@ -41,6 +43,7 @@ import java.util.*; import java.util.function.Consumer; import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.evolveum.midpoint.test.IntegrationTestTools.display; import static com.evolveum.midpoint.test.IntegrationTestTools.displayObjectTypeCollection; @@ -75,7 +78,7 @@ * - inducement MRx->Ry is of order 2 * - inducement MMRx->MRy is of order 1 * - * Each role has authorization, construction, focus mapping, focus policy rule and target policy rule. + * Each role has an authorization, GUI config, constructions, focus mappings, focus policy rules and target policy rules. * * Each assignment and each role can be selectively enabled/disabled (via activation) and has its condition matched (none/old/new/old+new). * @@ -114,142 +117,6 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti createObjects(false, initTask, initResult, null); } - private void createObjects(boolean deleteFirst, Task task, OperationResult result, Runnable adjustment) throws Exception { - role1 = createRole(1, 1); - role2 = createRole(1, 2); - org3 = createOrg(3); - role4 = createRole(1, 4); - role5 = createRole(1, 5); - role6 = createRole(1, 6); - metarole1 = createRole(2, 1); - metarole2 = createRole(2, 2); - metarole3 = createRole(2, 3); - metarole4 = createRole(2, 4); - metametarole1 = createRole(3, 1); - assign(role1, metarole1); - assign(role2, metarole2); - assign(metarole1, metametarole1); - induce(role1, role2, 1); - induce(metarole1, metarole3, 1); - induce(metarole1, role4, 2); - induce(metarole2, org3, 2); - induce(metarole3, role5, 2); - induce(metarole4, role6, 2); - induce(metametarole1, metarole4, 2); - - roles = Arrays - .asList(role1, role2, org3, role4, role5, role6, metarole1, metarole2, metarole3, metarole4, metametarole1); - - if (adjustment != null) { - adjustment.run(); - } - -// for (ObjectType role : roles) { -// System.out.println(prismContext.xmlSerializer().serialize(role.asPrismObject())); -// } - - // TODO implement repoAddObjects with overwrite option - if (deleteFirst) { - for (ObjectType role : roles) { - repositoryService.deleteObject(role.getClass(), role.getOid(), result); - } - } - - repoAddObjects(roles, result); - recomputeAndRefreshObjects(roles, task, result); - displayObjectTypeCollection("objects", roles); - } - - private void induce(AbstractRoleType source, AbstractRoleType target, int inducementOrder) { - AssignmentType inducement = ObjectTypeUtil.createAssignmentTo(target.asPrismObject()); - if (inducementOrder > 1) { - inducement.setOrder(inducementOrder); - } - source.getInducement().add(inducement); - } - - private void assign(RoleType source, RoleType target) { - AssignmentType assignment = ObjectTypeUtil.createAssignmentTo(target.asPrismObject()); - source.getAssignment().add(assignment); - } - - private RoleType createRole(int level, int number) { - return prepareAbstractRole(new RoleType(prismContext), level, number, "R"); - } - - private OrgType createOrg(int number) { - return prepareAbstractRole(new OrgType(prismContext), 1, number, "O"); - } - - private R prepareAbstractRole(R abstractRole, int level, int number, String nameSymbol) { - String name = StringUtils.repeat('M', level-1) + nameSymbol + number; - String oid = getRoleOid(name); - - abstractRole.setName(PolyStringType.fromOrig(name)); - abstractRole.setOid(oid); - - // constructions - for (int i = 0; i <= CONSTRUCTION_LEVELS; i++) { - ConstructionType c = new ConstructionType(prismContext); - c.setDescription(name + "-" + i); - c.setResourceRef(ObjectTypeUtil.createObjectRef(RESOURCE_DUMMY_EMPTY_OID, ObjectTypes.RESOURCE)); - AssignmentType a = new AssignmentType(prismContext); - a.setDescription("Assignment for " + c.getDescription()); - a.setConstruction(c); - addAssignmentOrInducement(abstractRole, i, a); - } - - // focus mappings - for (int i = 0; i <= FOCUS_MAPPING_LEVELS; i++) { - MappingType mapping = new MappingType(); - mapping.setName(name + "-" + i); - VariableBindingDefinitionType source = new VariableBindingDefinitionType(); - source.setPath(new ItemPath(UserType.F_NAME).asItemPathType()); - mapping.getSource().add(source); - VariableBindingDefinitionType target = new VariableBindingDefinitionType(); - target.setPath(new ItemPath(UserType.F_DESCRIPTION).asItemPathType()); - mapping.setTarget(target); - MappingsType mappings = new MappingsType(prismContext); - mappings.getMapping().add(mapping); - AssignmentType a = new AssignmentType(prismContext); - a.setFocusMappings(mappings); - addAssignmentOrInducement(abstractRole, i, a); - } - - // policy rules - for (int i = 0; i <= POLICY_RULES_LEVELS; i++) { - PolicyRuleType rule = new PolicyRuleType(prismContext); - rule.setName(name + "-" + i); - AssignmentType a = new AssignmentType(prismContext); - a.setPolicyRule(rule); - addAssignmentOrInducement(abstractRole, i, a); - } - - // authorization - AuthorizationType authorization = new AuthorizationType(prismContext); - authorization.getAction().add(name); - abstractRole.getAuthorization().add(authorization); - - // admin gui config - AdminGuiConfigurationType guiConfig = new AdminGuiConfigurationType(); - guiConfig.setPreferredDataLanguage(name); - abstractRole.setAdminGuiConfiguration(guiConfig); - return abstractRole; - } - - private void addAssignmentOrInducement(R abstractRole, int order, AssignmentType assignment) { - if (order == 0) { - abstractRole.getAssignment().add(assignment); - } else { - assignment.setOrder(order); - abstractRole.getInducement().add(assignment); - } - } - - private static String getRoleOid(String name) { - return "99999999-0000-0000-0000-" + StringUtils.repeat('0', 12-name.length()) + name; - } - @Test public void test010AssignR1ToJack() throws Exception { final String TEST_NAME = "test010AssignR1ToJack"; @@ -372,6 +239,10 @@ private void assertFocusPolicyRules(EvaluatedAssignmentImpl evaluatedA evaluatedAssignment.getFocusPolicyRules().stream().map(r -> r.getName()).collect(Collectors.toSet())); } + private void assertTargetPolicyRules(EvaluatedAssignmentImpl evaluatedAssignment, String expectedTargetItems, String expectedThisTargetItems) { + assertTargetPolicyRules(evaluatedAssignment, getList(expectedTargetItems), getList(expectedThisTargetItems)); + } + private void assertTargetPolicyRules(EvaluatedAssignmentImpl evaluatedAssignment, Collection expectedTargetItems, Collection expectedThisTargetItems) { expectedTargetItems = CollectionUtils.emptyIfNull(expectedTargetItems); expectedThisTargetItems = CollectionUtils.emptyIfNull(expectedThisTargetItems); @@ -393,6 +264,37 @@ private void assertTargetPolicyRules(EvaluatedAssignmentImpl evaluated } } + private void assertTargets(EvaluatedAssignmentImpl evaluatedAssignment, + String zeroValid, String zeroInvalid, + String plusValid, String plusInvalid, + String minusValid, String minusInvalid) { + assertTargets(evaluatedAssignment, getList(zeroValid), getList(zeroInvalid), + getList(plusValid), getList(plusInvalid), getList(minusValid), getList(minusInvalid)); + } + + private void assertTargets(EvaluatedAssignmentImpl evaluatedAssignment, + List zeroValid, List zeroInvalid, + List plusValid, List plusInvalid, + List minusValid, List minusInvalid) { + assertTargets("zero", evaluatedAssignment.getRoles().getZeroSet(), zeroValid, zeroInvalid); + assertTargets("plus", evaluatedAssignment.getRoles().getPlusSet(), plusValid, plusInvalid); + assertTargets("minus", evaluatedAssignment.getRoles().getMinusSet(), minusValid, minusInvalid); + } + + private void assertTargets(String type, Collection targets, List expectedValid, + List expectedInvalid) { + targets = CollectionUtils.emptyIfNull(targets); + Collection realValid = targets.stream().filter(t -> t.isValid()).collect(Collectors.toList()); + Collection realInvalid = targets.stream().filter(t -> !t.isValid()).collect(Collectors.toList()); + assertEquals("Wrong # of valid targets in " + type + " set", expectedValid.size(), realValid.size()); + assertEquals("Wrong # of invalid targets in " + type + " set", expectedInvalid.size(), realInvalid.size()); + assertEquals("Wrong valid targets in " + type + " set", new HashSet<>(expectedValid), + realValid.stream().map(t -> t.getTarget().getName().getOrig()).collect(Collectors.toSet())); + assertEquals("Wrong invalid targets in " + type + " set", new HashSet<>(expectedInvalid), + realInvalid.stream().map(t -> t.getTarget().getName().getOrig()).collect(Collectors.toSet())); + } + + private void assertConstructions(EvaluatedAssignmentImpl evaluatedAssignment, String zeroValid, String zeroInvalid, String plusValid, String plusInvalid, @@ -400,7 +302,7 @@ private void assertConstructions(EvaluatedAssignmentImpl evaluatedAssi assertConstructions(evaluatedAssignment, getList(zeroValid), getList(zeroInvalid), getList(plusValid), getList(plusInvalid), getList(minusValid), getList(minusInvalid)); } - + private void assertConstructions(EvaluatedAssignmentImpl evaluatedAssignment, List zeroValid, List zeroInvalid, List plusValid, List plusInvalid, @@ -432,7 +334,7 @@ private Collection assertAssignmentTripleSetSize(LensCo return context.getEvaluatedAssignmentTriple().getAllValues(); } - @Test(enabled = false) + @Test public void test020AssignR1ToJackProjectorDisabled() throws Exception { final String TEST_NAME = "test020AssignR1ToJackProjectorDisabled"; TestUtil.displayTestTile(this, TEST_NAME); @@ -475,6 +377,8 @@ private LensContext createContextForRoleAssignment(String userOid, Str } /** + * Now disable some roles. Their administrative status is simply set to DISABLED. + * * MMR1(D)---------I------------------------------* * ^ | * | I @@ -500,29 +404,12 @@ public void test100DisableSomeRoles() throws Exception { OperationResult result = task.getResult(); // WHEN - createObjects(true, task, result, () -> { - disableRoles("MMR1 R2 MR3 R4"); - }); + createObjects(true, task, result, () -> disableRoles("MMR1 R2 MR3 R4")); // THEN - - } - - private void disableRoles(String rolesText) { - List roleNames = getList(rolesText); - for (String name : roleNames) { - AbstractRoleType role = findRole(name); - if (role.getActivation() == null) { - role.setActivation(new ActivationType(prismContext)); - } - role.getActivation().setAdministrativeStatus(ActivationStatusType.DISABLED); - } + // TODO check e.g. membershipRef for roles } - private AbstractRoleType findRole(String name) { - return (AbstractRoleType) roles.stream().filter(r -> name.equals(r.getName().getOrig())).findFirst() - .orElseThrow(() -> new IllegalStateException("No role " + name)); - } @Test public void test110AssignR1ToJack() throws Exception { @@ -559,10 +446,6 @@ public void test110AssignR1ToJack() throws Exception { assertFocusMappings(evaluatedAssignment, expectedItems); assertFocusPolicyRules(evaluatedAssignment, expectedItems); - // TODO why R4-0 R5-0 R6-0 ? Sounds not good: when we are adding R1 assignment, we are not interested - // in approval rules residing in induced roles, even if they are induced through a higher levels - // (in the same way as we are not interested in R2-0 and R3-0) - // MR3-1 MR4-1 seems to be OK; these are induced in a quite intuitive way (via MR1) String expectedThisTargetRules = "R1-0 MR1-1"; String expectedTargetRules = expectedThisTargetRules; assertTargetPolicyRules(evaluatedAssignment, getList(expectedTargetRules), getList(expectedThisTargetRules)); @@ -571,41 +454,103 @@ public void test110AssignR1ToJack() throws Exception { } - private void assertDelegation(EvaluatedAssignmentImpl evaluatedAssignment, String text) { - assertPrismRefValues("delegationRef", evaluatedAssignment.getDelegationRefVals(), findRoles(text)); - } + /** + * In a similar way, let's disable some assignments. Their administrative status is simply set to DISABLED. + * + * MMR1 -----------I------------------------------* + * ^ | + * | I + * | V + * MR1 -----------I-------------*-(D)-> MR3 MR4 + * ^ MR2 --I---* | | | + * | ^ I I I I(D) + * | | V V V V + * R1-I(D)-> R2 O3 R4 R5 R6 + * ^ + * | + * | + * jack + */ - private void assertOrgRef(EvaluatedAssignmentImpl evaluatedAssignment, String text) { - assertPrismRefValues("orgRef", evaluatedAssignment.getOrgRefVals(), findRoles(text)); - } + @Test + public void test150DisableSomeAssignments() throws Exception { + final String TEST_NAME = "test150DisableSomeAssignments"; + TestUtil.displayTestTile(this, TEST_NAME); - private void assertMembershipRef(EvaluatedAssignmentImpl evaluatedAssignment, String text) { - assertPrismRefValues("membershipRef", evaluatedAssignment.getMembershipRefVals(), findRoles(text)); + // GIVEN + Task task = taskManager.createTaskInstance(TestAssignmentProcessor.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + createObjects(true, task, result, () -> disableAssignments("MR4-R6 MR1-MR3 R1-R2")); + + // THEN } - private List findRoles(String text) { - return getList(text).stream().map(n -> findRole(n)).collect(Collectors.toList()); + @Test + public void test160AssignR1ToJack() throws Exception { + final String TEST_NAME = "test160AssignR1ToJack"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestAssignmentProcessor.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + LensContext context = createContextForRoleAssignment(USER_JACK_OID, R1_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 evaluatedAssignments = assertAssignmentTripleSetSize(context, 0, 1, 0); + EvaluatedAssignmentImpl evaluatedAssignment = evaluatedAssignments.iterator().next(); + assertEquals("Wrong evaluatedAssignment.isValid", true, evaluatedAssignment.isValid()); + + assertMembershipRef(evaluatedAssignment, "R1 R4"); + assertOrgRef(evaluatedAssignment, null); + assertDelegation(evaluatedAssignment, null); + + String expectedItems = "R1-1 MR1-2 MMR1-3 MR4-2 R4-1"; + assertConstructions(evaluatedAssignment, expectedItems, null, null, null, null, null); + assertFocusMappings(evaluatedAssignment, expectedItems); + assertFocusPolicyRules(evaluatedAssignment, expectedItems); + + String expectedThisTargetRules = "R1-0 MR1-1 MMR1-2 MR4-1 R4-0"; // TODO why R4-0 ? + String expectedTargetRules = expectedThisTargetRules; + assertTargetPolicyRules(evaluatedAssignment, getList(expectedTargetRules), getList(expectedThisTargetRules)); + assertAuthorizations(evaluatedAssignment, "R1 R4"); + assertGuiConfig(evaluatedAssignment, "R1 R4"); + } /** - * MMR1 -----------I------------------------------* + * Let's attach some conditions to assignments and roles. "+" condition means that it will be satisfied only in jack's new state. + * "-" condition will be satisfied only in jack's old state. "0" condition will be never satisfied. + * + * MMR1------------I------------------------------* * ^ | - * | I + * (+) I * | V - * MR1 -----------I-------------*-----> MR3 MR4 + * (+)MR1 -----------I-------------*-----> MR3(0) MR4(-) * ^ MR2 --I---* | | | - * | ^ I I I I(D) + * (+) ^ (+) I I I I * | | V V V V - * R1 --I--> R2 O3 R4 R5 R6 - * ^ + * R1 --I--> R2 O3 R4(D) R5 R6 + * ^ (-) * | * | * jack */ @Test - public void test200DisableSomeAssignments() throws Exception { - final String TEST_NAME = "test200DisableSomeAssignments"; + public void test200AddConditions() throws Exception { + final String TEST_NAME = "test200AddConditions"; TestUtil.displayTestTile(this, TEST_NAME); // GIVEN @@ -614,11 +559,287 @@ public void test200DisableSomeAssignments() throws Exception { // WHEN createObjects(true, task, result, () -> { - disableRoles("MMR1 R2 MR3 R4"); + disableRoles("R4"); + addConditionToRoles("MR1+ MR30 MR4-"); + addConditionToAssignments("R1-MR1+ MR1-MMR1+ R1-R2- MR2-O3+"); }); // THEN + // TODO check e.g. membershipRef for roles + } + + + @Test + public void test210AssignR1ToJack() throws Exception { + final String TEST_NAME = "test210AssignR1ToJack"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestAssignmentProcessor.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + LensContext context = createContextForRoleAssignment(USER_JACK_OID, R1_OID, null, null, result); + context.getFocusContext().swallowToPrimaryDelta( + DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_NAME).replace(PolyString.fromOrig("jack1")) + .asItemDelta()); + + // 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 evaluatedAssignments = assertAssignmentTripleSetSize(context, 0, 1, 0); + EvaluatedAssignmentImpl evaluatedAssignment = evaluatedAssignments.iterator().next(); + assertEquals("Wrong evaluatedAssignment.isValid", true, evaluatedAssignment.isValid()); + + // R4 is not in plusInvalid, because only directly assigned targets are listed among targets (see validityOverride) + assertTargets(evaluatedAssignment, "R1", null, "MR1 MMR1", null, "R2 MR2", null); + assertMembershipRef(evaluatedAssignment, "R1"); + assertOrgRef(evaluatedAssignment, null); + assertDelegation(evaluatedAssignment, null); + + // R4-1 is not in plusInvalid (see above) + assertConstructions(evaluatedAssignment, "R1-1", null, "MR1-2 MMR1-3", null, "R2-1 MR2-2", null); + assertFocusMappings(evaluatedAssignment, "R1-1 MR1-2 MMR1-3"); + assertFocusPolicyRules(evaluatedAssignment, "R1-1 MR1-2 MMR1-3"); + + assertTargetPolicyRules(evaluatedAssignment, "R1-0 MR1-1 MMR1-2", "R1-0 MR1-1 MMR1-2"); + assertAuthorizations(evaluatedAssignment, "R1"); + assertGuiConfig(evaluatedAssignment, "R1"); + } + + + private void disableRoles(String text) { + for (String name : getList(text)) { + AbstractRoleType role = findRole(name); + if (role.getActivation() == null) { + role.setActivation(new ActivationType(prismContext)); + } + role.getActivation().setAdministrativeStatus(ActivationStatusType.DISABLED); + } + } + + private void addConditionToRoles(String text) { + for (String item : getList(text)) { + String name = StringUtils.substring(item, 0, -1); + char conditionType = item.charAt(item.length() - 1); + AbstractRoleType role = findRole(name); + role.setCondition(createCondition(conditionType)); + } + } + + private void disableAssignments(String text) { + for (String assignmentText : getList(text)) { + AssignmentType assignment = findAssignmentOrInducement(assignmentText); + if (assignment.getActivation() == null) { + assignment.setActivation(new ActivationType(prismContext)); + } + assignment.getActivation().setAdministrativeStatus(ActivationStatusType.DISABLED); + } + } + + private AssignmentType findAssignmentOrInducement(String assignmentText) { + String[] split = StringUtils.split(assignmentText, "-"); + AbstractRoleType source = findRole(split[0]); + AbstractRoleType target = findRole(split[1]); + return findAssignmentOrInducement(source, target); + } + + private void addConditionToAssignments(String text) { + for (String item : getList(text)) { + String assignmentText = StringUtils.substring(item, 0,-1); + char conditionType = item.charAt(item.length() - 1); + AssignmentType assignment = findAssignmentOrInducement(assignmentText); + assignment.setCondition(createCondition(conditionType)); + } + } + + private MappingType createCondition(char conditionType) { + ScriptExpressionEvaluatorType script = new ScriptExpressionEvaluatorType(); + switch (conditionType) { + case '+': script.setCode("basic.stringify(name) == 'jack1'"); break; + case '-': script.setCode("basic.stringify(name) == 'jack'"); break; + case '0': script.setCode("basic.stringify(name) == 'never there'"); break; + default: throw new AssertionError(conditionType); + } + ExpressionType expression = new ExpressionType(); + expression.getExpressionEvaluator().add(new ObjectFactory().createScript(script)); + VariableBindingDefinitionType source = new VariableBindingDefinitionType(); + source.setPath(new ItemPath(UserType.F_NAME).asItemPathType()); + MappingType rv = new MappingType(); + rv.setExpression(expression); + rv.getSource().add(source); + return rv; + } + + private AssignmentType findAssignmentOrInducement(AbstractRoleType source, AbstractRoleType target) { + return Stream.concat(source.getAssignment().stream(), source.getInducement().stream()) + .filter(a -> a.getTargetRef() != null && target.getOid().equals(a.getTargetRef().getOid())) + .findFirst() + .orElseThrow(() -> new IllegalStateException(source + " contains no assignment/inducement to " + target)); + } + + private AbstractRoleType findRole(String name) { + return (AbstractRoleType) roles.stream().filter(r -> name.equals(r.getName().getOrig())).findFirst() + .orElseThrow(() -> new IllegalStateException("No role " + name)); + } + + private void assertDelegation(EvaluatedAssignmentImpl evaluatedAssignment, String text) { + assertPrismRefValues("delegationRef", evaluatedAssignment.getDelegationRefVals(), findRoles(text)); + } + + private void assertOrgRef(EvaluatedAssignmentImpl evaluatedAssignment, String text) { + assertPrismRefValues("orgRef", evaluatedAssignment.getOrgRefVals(), findRoles(text)); + } + + private void assertMembershipRef(EvaluatedAssignmentImpl evaluatedAssignment, String text) { + assertPrismRefValues("membershipRef", evaluatedAssignment.getMembershipRefVals(), findRoles(text)); + } + + private List findRoles(String text) { + return getList(text).stream().map(n -> findRole(n)).collect(Collectors.toList()); + } + + private void induce(AbstractRoleType source, AbstractRoleType target, int inducementOrder) { + AssignmentType inducement = ObjectTypeUtil.createAssignmentTo(target.asPrismObject()); + if (inducementOrder > 1) { + inducement.setOrder(inducementOrder); + } + source.getInducement().add(inducement); + } + + private void assign(RoleType source, RoleType target) { + AssignmentType assignment = ObjectTypeUtil.createAssignmentTo(target.asPrismObject()); + source.getAssignment().add(assignment); + } + + private RoleType createRole(int level, int number) { + return prepareAbstractRole(new RoleType(prismContext), level, number, "R"); + } + + private OrgType createOrg(int number) { + return prepareAbstractRole(new OrgType(prismContext), 1, number, "O"); + } + + private R prepareAbstractRole(R abstractRole, int level, int number, String nameSymbol) { + String name = StringUtils.repeat('M', level-1) + nameSymbol + number; + String oid = getRoleOid(name); + + abstractRole.setName(PolyStringType.fromOrig(name)); + abstractRole.setOid(oid); + + // constructions + for (int i = 0; i <= CONSTRUCTION_LEVELS; i++) { + ConstructionType c = new ConstructionType(prismContext); + c.setDescription(name + "-" + i); + c.setResourceRef(ObjectTypeUtil.createObjectRef(RESOURCE_DUMMY_EMPTY_OID, ObjectTypes.RESOURCE)); + AssignmentType a = new AssignmentType(prismContext); + a.setDescription("Assignment for " + c.getDescription()); + a.setConstruction(c); + addAssignmentOrInducement(abstractRole, i, a); + } + + // focus mappings + for (int i = 0; i <= FOCUS_MAPPING_LEVELS; i++) { + MappingType mapping = new MappingType(); + mapping.setName(name + "-" + i); + VariableBindingDefinitionType source = new VariableBindingDefinitionType(); + source.setPath(new ItemPath(UserType.F_NAME).asItemPathType()); + mapping.getSource().add(source); + VariableBindingDefinitionType target = new VariableBindingDefinitionType(); + target.setPath(new ItemPath(UserType.F_DESCRIPTION).asItemPathType()); + mapping.setTarget(target); + MappingsType mappings = new MappingsType(prismContext); + mappings.getMapping().add(mapping); + AssignmentType a = new AssignmentType(prismContext); + a.setFocusMappings(mappings); + addAssignmentOrInducement(abstractRole, i, a); + } + + // policy rules + for (int i = 0; i <= POLICY_RULES_LEVELS; i++) { + PolicyRuleType rule = new PolicyRuleType(prismContext); + rule.setName(name + "-" + i); + AssignmentType a = new AssignmentType(prismContext); + a.setPolicyRule(rule); + addAssignmentOrInducement(abstractRole, i, a); + } + + // authorization + AuthorizationType authorization = new AuthorizationType(prismContext); + authorization.getAction().add(name); + abstractRole.getAuthorization().add(authorization); + // admin gui config + AdminGuiConfigurationType guiConfig = new AdminGuiConfigurationType(); + guiConfig.setPreferredDataLanguage(name); + abstractRole.setAdminGuiConfiguration(guiConfig); + return abstractRole; + } + + private void addAssignmentOrInducement(R abstractRole, int order, AssignmentType assignment) { + if (order == 0) { + abstractRole.getAssignment().add(assignment); + } else { + assignment.setOrder(order); + abstractRole.getInducement().add(assignment); + } + } + + private static String getRoleOid(String name) { + return "99999999-0000-0000-0000-" + StringUtils.repeat('0', 12-name.length()) + name; + } + + private void createObjects(boolean deleteFirst, Task task, OperationResult result, Runnable adjustment) throws Exception { + role1 = createRole(1, 1); + role2 = createRole(1, 2); + org3 = createOrg(3); + role4 = createRole(1, 4); + role5 = createRole(1, 5); + role6 = createRole(1, 6); + metarole1 = createRole(2, 1); + metarole2 = createRole(2, 2); + metarole3 = createRole(2, 3); + metarole4 = createRole(2, 4); + metametarole1 = createRole(3, 1); + assign(role1, metarole1); + assign(role2, metarole2); + assign(metarole1, metametarole1); + induce(role1, role2, 1); + induce(metarole1, metarole3, 1); + induce(metarole1, role4, 2); + induce(metarole2, org3, 2); + induce(metarole3, role5, 2); + induce(metarole4, role6, 2); + induce(metametarole1, metarole4, 2); + + roles = Arrays + .asList(role1, role2, org3, role4, role5, role6, metarole1, metarole2, metarole3, metarole4, metametarole1); + + if (adjustment != null) { + adjustment.run(); + } + + // for (ObjectType role : roles) { + // System.out.println(prismContext.xmlSerializer().serialize(role.asPrismObject())); + // } + + // TODO implement repoAddObjects with overwrite option + if (deleteFirst) { + for (ObjectType role : roles) { + repositoryService.deleteObject(role.getClass(), role.getOid(), result); + } + } + + repoAddObjects(roles, result); + recomputeAndRefreshObjects(roles, task, result); + displayObjectTypeCollection("objects", roles); } }