Skip to content

Commit

Permalink
Allow creating draft objects in org tree
Browse files Browse the repository at this point in the history
When creating objects in the org tree, GUI creates both
assignments and parentOrgRef values, see MID-3234. This commit
removes parentOrgRef values if they should not be there in case
that object itself is in "assignments inactive" LC state. See the
AbstractPageObjectDetails#removeExtraParentOrgRef javadoc.

Should resolve MID-9264.
  • Loading branch information
mederly committed Jan 18, 2024
1 parent dcfe00b commit 1a35cff
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
import com.evolveum.midpoint.gui.api.util.WebPrismUtil;
import com.evolveum.midpoint.gui.impl.component.menu.LeftMenuAuthzUtil;

import com.evolveum.midpoint.model.common.archetypes.ArchetypeManager;
import com.evolveum.midpoint.schema.TaskExecutionMode;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.web.security.MidPointApplication;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
Expand All @@ -26,6 +31,7 @@
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.evolveum.midpoint.gui.api.component.result.MessagePanel;
Expand Down Expand Up @@ -304,6 +310,13 @@ public Collection<ObjectDeltaOperation<? extends ObjectType>> saveOrPreviewPerfo
deltas = getObjectDetailsModels().collectDeltas(result);
}
checkValidationErrors(target, objectDetailsModels.getValidationErrors());

for (ObjectDelta<? extends ObjectType> delta : deltas) {
if (delta.isAdd()) {
removeExtraParentOrgRef(delta.getObjectToAdd().asObjectable());
}
}

} catch (Throwable ex) {
result.recordFatalError(getString("pageAdminObjectDetails.message.cantCreateObject"), ex);
LoggingUtils.logUnexpectedException(LOGGER, "Create Object failed", ex);
Expand All @@ -326,6 +339,53 @@ public Collection<ObjectDeltaOperation<? extends ObjectType>> saveOrPreviewPerfo
return executedDeltas;
}

/**
* Removes `parentOrgRef` values from a to-be-created object that should not be there, because of the object's inactivity.
*
* == Rationale
*
* Because of the authorization requirements (both when the object editing starts - see edit schema,
* and when the operation is submitted to execution), we manually set-up a `parentOrgRef` value for each org assignment
* that is pre-created in the new object. This is typically when the object is created as a child in a given org via GUI:
* The GUI creates the respective org assignment and `parentOrgRef` value.
*
* (Note that this is not wholly correct, and is more a workaround than a real solution. The real solution would be
* to either call the projector to do this, or to change the authorization evaluation to not depend on `parentOrgRef`.
* That way or another, it is currently so. See also MID-3234.)
*
* The problem occurs when the object is changed to `draft` or similar LC state during editing. The added `parentOrgRef`
* should no longer be there, as the current implementation is that the org assignment(s) are inactive in such object LC
* states (unless the state model says otherwise). If they are present and should not be, the model refuses
* the ADD operation (see MID-9264). So this method removes them.
*
* == Limitations
*
* We do NOT treat general cases here, like when the respective assignment itself is modified (e.g.,
* disabled, validity changed, LC state changed, etc.). We only treat the case when the object as a whole is
* put into "assignments inactive" LC state.
*/
private void removeExtraParentOrgRef(@NotNull ObjectType object) throws ConfigurationException {
if (!(object instanceof AssignmentHolderType)) {
return; // There are no assignments to be considered
}

SystemConfigurationType config = MidPointApplication.get().getSystemConfigurationIfAvailable();
LifecycleStateModelType objectStateModel =
ArchetypeManager.determineLifecycleModel(object.asPrismObject(), config);

// As for the task execution mode is concerned, we are interested only in whether production or development config
// is to be used. Currently, all GUI "object details page" actions are carried out in production mode. So we can
// safely use TaskExecutionMode.PRODUCTION here.
boolean assignmentsActive = MidPointApplication.get().getActivationComputer().lifecycleHasActiveAssignments(
object.getLifecycleState(), objectStateModel, TaskExecutionMode.PRODUCTION);

if (!assignmentsActive) {
// We assume that this is a new object. All parentOrgRef values should come through assignments.
// Hence, if assignments are not active, we can remove all such values.
object.getParentOrgRef().clear();
}
}

protected void postProcessResultForWizard(
OperationResult result,
Collection<ObjectDeltaOperation<? extends ObjectType>> executedDeltas,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,6 @@ private boolean isAllowDelete(OrgType org) {
return allowDelete;
}

// TODO: merge this with AbstractRoleMemberPanel.initObjectForAdd, also see MID-3233
private <O extends ObjectType> void initObjectForAdd(ObjectReferenceType parentOrgRef, AjaxRequestTarget target) throws SchemaException {
TreeTablePanel.this.getPageBase().hideMainPopup(target);
PrismContext prismContext = TreeTablePanel.this.getPageBase().getPrismContext();
Expand All @@ -500,6 +499,7 @@ private <O extends ObjectType> void initObjectForAdd(ObjectReferenceType parentO
// The parentOrgRef should be added by the projector. But
// this is needed to successfully pass through security
// TODO: fix MID-3234
// see also DetailsPageUtil.initNewObjectWithReference
if (parentOrgRef == null) {
ObjectType org = getTreePanel().getSelected().getValue();
parentOrgRef = ObjectTypeUtil.createObjectRef(org, prismContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ public static <AHT extends AssignmentHolderType> void initNewObjectWithReference
// The parentOrgRef should be added by the projector. But
// this is needed to successfully pass through security
// TODO: fix MID-3234
// see also TreeTablePanel.initObjectForAdd
if (ref.getType() != null && OrgType.COMPLEX_TYPE.equals(ref.getType())) {
if (ref.getRelation() == null || pageBase.getRelationRegistry().isStoredIntoParentOrgRef(ref.getRelation())) {
assignmentHolder.getParentOrgRef().add(ref.clone());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.nio.charset.StandardCharsets;
import java.util.*;

import com.evolveum.midpoint.common.ActivationComputer;
import com.evolveum.midpoint.model.api.mining.RoleAnalysisService;

import com.evolveum.midpoint.repo.common.util.SubscriptionWrapper;
Expand Down Expand Up @@ -202,6 +203,7 @@ public class MidPointApplication extends AuthenticatedWebApplication implements
@Autowired private SystemConfigurationChangeDispatcher systemConfigurationChangeDispatcher;
@Autowired private Clock clock;
@Autowired private AccessCertificationService certificationService;
@Autowired private ActivationComputer activationComputer;
@Autowired(required = false) private List<WicketConfigurator> wicketConfigurators = new ArrayList<>();
@Autowired @Qualifier("descriptorLoader") private DescriptorLoader descriptorLoader;
@Value("${midpoint.additionalPackagesToScan:}") private String additionalPackagesToScan;
Expand Down Expand Up @@ -591,6 +593,10 @@ public AccessCertificationService getCertificationService() {
return certificationService;
}

public ActivationComputer getActivationComputer() {
return activationComputer;
}

public static boolean containsLocale(Locale locale) {
if (locale == null) {
return false;
Expand Down

0 comments on commit 1a35cff

Please sign in to comment.