diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java index ac085fdc41e..e3b771b074d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java @@ -1117,4 +1117,31 @@ public static LensContext.ExportType getExportTypeTraceOrReduced(TraceType trace public static ItemDelta getAprioriItemDelta(ObjectDelta focusDelta, ItemPath itemPath) { return focusDelta != null ? focusDelta.findItemDelta(itemPath) : null; } + + public static String determineExplicitArchetypeOid(PrismObject object) { + String explicitArchetypeOid = null; + // Used in cases where archetype assignment haven't had the change to be processed yet. + // E.g. in case that we are creating a new object with archetype assignment + if (object.canRepresent(AssignmentHolderType.class)) { + AssignmentHolderType assignmentHolderType = (AssignmentHolderType)object.asObjectable(); + List archetypeRefs = assignmentHolderType.getArchetypeRef(); + if (archetypeRefs.isEmpty()) { + explicitArchetypeOid = determineExplicitArchetypeOidFromAssignments(object); + } + } + return explicitArchetypeOid; + } + + public static String determineExplicitArchetypeOidFromAssignments(PrismObject object) { + String explicitArchetypeOid = null; + if (object.canRepresent(AssignmentHolderType.class)) { + for (AssignmentType assignment : ((AssignmentHolderType)object.asObjectable()).getAssignment()) { + ObjectReferenceType targetRef = assignment.getTargetRef(); + if (targetRef != null && QNameUtil.match(ArchetypeType.COMPLEX_TYPE, targetRef.getType())) { + explicitArchetypeOid = targetRef.getOid(); + } + } + } + return explicitArchetypeOid; + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java index 60fb499776e..e9e8c0d4c0c 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java @@ -504,7 +504,7 @@ private ArchetypePolicyType determineArchetypePolicy(Lens return null; } PrismObject object = context.getFocusContext().getObjectAny(); - String explicitArchetypeOid = determineExplicitArchetypeOid(context); + String explicitArchetypeOid = LensUtil.determineExplicitArchetypeOid(context.getFocusContext().getObjectAny()); return archetypeManager.determineArchetypePolicy(object, explicitArchetypeOid, result); } @@ -519,7 +519,7 @@ public ArchetypeType updateArchetype(LensContex PrismObject object = context.getFocusContext().getObjectAny(); - String explicitArchetypeOid = determineExplicitArchetypeOid(context); + String explicitArchetypeOid = LensUtil.determineExplicitArchetypeOid(context.getFocusContext().getObjectAny()); PrismObject archetype = archetypeManager.determineArchetype(object, explicitArchetypeOid, result); ArchetypeType archetypeType = null; if (archetype != null) { @@ -531,26 +531,6 @@ public ArchetypeType updateArchetype(LensContex return archetypeType; } - private String determineExplicitArchetypeOid(LensContext context) { - PrismObject object = context.getFocusContext().getObjectAny(); - String explicitArchetypeOid = null; - // Used in cases where archetype assignment haven't had the change to be processed yet. - // E.g. in case that we are creating a new object with archetype assignment - if (object.canRepresent(AssignmentHolderType.class)) { - AssignmentHolderType assignmentHolderType = (AssignmentHolderType)object.asObjectable(); - List archetypeRefs = assignmentHolderType.getArchetypeRef(); - if (archetypeRefs.isEmpty()) { - for (AssignmentType assignment : assignmentHolderType.getAssignment()) { - ObjectReferenceType targetRef = assignment.getTargetRef(); - if (targetRef != null && QNameUtil.match(ArchetypeType.COMPLEX_TYPE, targetRef.getType())) { - explicitArchetypeOid = targetRef.getOid(); - } - } - } - } - return explicitArchetypeOid; - } - public void updateArchetypePolicy(LensContext context, Task task, OperationResult result) throws SchemaException, ConfigurationException { if (context.getFocusContext() == null) { return; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentHolderProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentHolderProcessor.java index 951f1884496..ac5c8a3a090 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentHolderProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentHolderProcessor.java @@ -119,6 +119,8 @@ private void processFocusFocus(LensContext LensFocusContext focusContext = context.getFocusContext(); PartialProcessingOptionsType partialProcessingOptions = context.getPartialProcessingOptions(); + checkArchetypeRefDelta(context); + boolean resetOnRename = true; // This is fixed now. TODO: make it configurable boolean wasResetOnIterationSpecificationChange = false; @@ -808,6 +810,36 @@ private void addIterationTokenDeltas(LensFocus } + private void checkArchetypeRefDelta(LensContext context) throws PolicyViolationException { + ObjectDelta focusPrimaryDelta = context.getFocusContext().getPrimaryDelta(); + if (focusPrimaryDelta != null) { + ReferenceDelta archetypeRefDelta = focusPrimaryDelta.findReferenceModification(AssignmentHolderType.F_ARCHETYPE_REF); + if (archetypeRefDelta != null) { + // We want to allow this under special circumstances. E.g. we want be able to import user with archetypeRef. + // Otherwise we won't be able to export a user and re-import it again. + if (focusPrimaryDelta.isAdd()) { + String archetypeOidFromAssignments = LensUtil.determineExplicitArchetypeOidFromAssignments(focusPrimaryDelta.getObjectToAdd()); + if (archetypeOidFromAssignments == null) { + throw new PolicyViolationException("Attempt add archetypeRef without a matching assignment"); + } else { + boolean match = true; + for (PrismReferenceValue archetypeRefDeltaVal : archetypeRefDelta.getValuesToAdd()) { + if (!archetypeOidFromAssignments.equals(archetypeRefDeltaVal.getOid())) { + match = false; + } + } + if (match) { + return; + } else { + throw new PolicyViolationException("Attempt add archetypeRef that does not match assignment"); + } + } + } + throw new PolicyViolationException("Attempt to modify archetypeRef directly"); + } + } + } + // private void processAssignmentActivation(LensContext context, XMLGregorianCalendar now, // OperationResult result) throws SchemaException { // DeltaSetTriple> evaluatedAssignmentTriple = context.getEvaluatedAssignmentTriple(); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentProcessor.java index 54b903e4114..f13e3cea53d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/AssignmentProcessor.java @@ -1097,14 +1097,6 @@ public void processMembershipAndDelegatedRefs(LensContext return; } - ObjectDelta focusPrimaryDelta = focusContext.getPrimaryDelta(); - if (focusPrimaryDelta != null) { - ReferenceDelta archetypeRefDelta = focusPrimaryDelta.findReferenceModification(AssignmentHolderType.F_ARCHETYPE_REF); - if (archetypeRefDelta != null) { - throw new PolicyViolationException("Attempt to modify archetypeRef directly"); - } - } - Collection shouldBeRoleRefs = new ArrayList<>(); Collection shouldBeDelegatedRefs = new ArrayList<>(); Collection shouldBeArchetypeRefs = new ArrayList<>(); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestArchetypes.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestArchetypes.java index 001e6c5b1aa..52ecea17632 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestArchetypes.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/archetypes/TestArchetypes.java @@ -12,6 +12,7 @@ import java.io.File; +import com.evolveum.midpoint.util.exception.*; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.test.context.ContextConfiguration; @@ -32,13 +33,6 @@ import com.evolveum.midpoint.schema.util.ObjectQueryUtil; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.CommonException; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ArchetypeType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentPolicyEnforcementType; @@ -83,6 +77,12 @@ public class TestArchetypes extends AbstractArchetypesTest { public static final File USER_WANNABE_FILE = new File(TEST_DIR, "user-wannabe.xml"); protected static final String USER_WANNABE_OID = "28038d88-d3eb-11e9-87fb-cff5e050b6f9"; + public static final File USER_SELF_MADE_MAN_FILE = new File(TEST_DIR, "user-self-made-man.xml"); + protected static final String USER_SELF_MADE_MAN_OID = "065c4592-0787-11ea-af06-f7eae18b6b4a"; + + public static final File USER_FRAUDSTER_FILE = new File(TEST_DIR, "user-fraudster.xml"); + protected static final String USER_FRAUDSTER_OID = "99b36382-078e-11ea-b9a9-b393552ec165"; + public static final File ROLE_EMPLOYEE_BASE_FILE = new File(TEST_DIR, "role-employee-base.xml"); protected static final String ROLE_EMPLOYEE_BASE_OID = "e869d6c4-f6ef-11e8-b51f-df3e51bba129"; @@ -771,17 +771,86 @@ public void test150AddWannabe() throws Exception { assertUserAfter(USER_WANNABE_OID) .assertLifecycleState(SchemaConstants.LIFECYCLE_DRAFT) .assignments() - .assertAssignments(1) - .assertArchetype(ARCHETYPE_CONTRACTOR_OID) - .end() + .assertAssignments(1) + .assertArchetype(ARCHETYPE_CONTRACTOR_OID) + .end() .assertArchetypeRef(ARCHETYPE_CONTRACTOR_OID) .roleMembershipRefs() - .assertRoleMemberhipRefs(1) - .assertArchetype(ARCHETYPE_CONTRACTOR_OID) - .end() + .assertRoleMemberhipRefs(1) + .assertArchetype(ARCHETYPE_CONTRACTOR_OID) + .end() .assertEmployeeNumber(CONTRACTOR_EMPLOYEE_NUMBER); } + /** + * Add "Self Made Man" user with an archetypeRef. We usually do not allow archetypeRef. But in this case the ref + * matches the assignment. We want to allow this. If we do not allow this, then we cannot re-import a "made" user. + * MID-5909 + */ + @Test + public void test160AddSelfMadeMan() throws Exception { + final String TEST_NAME = "test160AddSelfMadeMan"; + displayTestTitle(TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + displayWhen(TEST_NAME); + + addObject(USER_SELF_MADE_MAN_FILE, task, result); + + // THEN + displayThen(TEST_NAME); + assertSuccess(result); + + assertUserAfter(USER_SELF_MADE_MAN_OID) + .assignments() + .assertAssignments(1) + .assertArchetype(ARCHETYPE_CONTRACTOR_OID) + .end() + .assertArchetypeRef(ARCHETYPE_CONTRACTOR_OID) + .roleMembershipRefs() + .assertRoleMemberhipRefs(1) + .assertArchetype(ARCHETYPE_CONTRACTOR_OID) + .end(); + } + + /** + * Add "fraudster" user with an archetypeRef. In this case the archetypeRef does not match the assignment. + * This operation shoudl be denied. + * MID-5909 + */ + @Test + public void test162AddFraudster() throws Exception { + final String TEST_NAME = "test162AddFraudster"; + displayTestTitle(TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + // precondition + assertNoObject(UserType.class, USER_FRAUDSTER_OID); + + try { + // WHEN + displayWhen(TEST_NAME); + + addObject(USER_FRAUDSTER_FILE, task, result); + + assertNotReached(); + } catch (PolicyViolationException e) { + // Expected + display("Expected exception", e); + } + + // THEN + displayThen(TEST_NAME); + assertFailure(result); + + assertNoObject(UserType.class, USER_FRAUDSTER_OID); + } + @Test public void test200AssignJackBarbossaArchetypeEmployee() throws Exception { final String TEST_NAME = "test200AssignJackBarbossaArchetypeEmployee"; diff --git a/model/model-intest/src/test/resources/archetypes/user-fraudster.xml b/model/model-intest/src/test/resources/archetypes/user-fraudster.xml new file mode 100644 index 00000000000..0ec5bf388cd --- /dev/null +++ b/model/model-intest/src/test/resources/archetypes/user-fraudster.xml @@ -0,0 +1,24 @@ + + + + + fraudster + + + + + + + Fraudster + diff --git a/model/model-intest/src/test/resources/archetypes/user-self-made-man.xml b/model/model-intest/src/test/resources/archetypes/user-self-made-man.xml new file mode 100644 index 00000000000..bdbad22a61b --- /dev/null +++ b/model/model-intest/src/test/resources/archetypes/user-self-made-man.xml @@ -0,0 +1,23 @@ + + + + + selfmademan + + + + + + Self Made Man + diff --git a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java index ddfbabd4e14..2981303cc34 100644 --- a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java +++ b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java @@ -1752,7 +1752,7 @@ protected void assertNoObject(Class type, String oid) protected void assertNoObject(Class type, String oid, Task task, OperationResult result) throws SchemaException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { try { PrismObject object = modelService.getObject(type, oid, null, task, result); - + display("Unexpected object", object); AssertJUnit.fail("Expected that "+object+" does not exist, but it does"); } catch (ObjectNotFoundException e) { // This is expected