diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AbstractRoleAssignmentPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AbstractRoleAssignmentPanel.java index bfd55471ea7..b3ab0fb4505 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AbstractRoleAssignmentPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AbstractRoleAssignmentPanel.java @@ -151,28 +151,24 @@ protected void addSelectedAssignmentsPerformed(AjaxReques target.add(getPageBase().getFeedbackPanel()); return; } - ContainerWrapperFactory factory = new ContainerWrapperFactory(getPageBase()); + for (T object : assignmentsList){ -// ContainerWrapper newAssignmentContainer = factory.createContainerWrapper(object.asPrismContainerValue().getContainer(), -// ContainerStatus.ADDING, new ItemPath(FocusType.F_ASSIGNMENT)); - - ObjectReferenceType ort = new ObjectReferenceType(); - ort.setOid(object.getOid()); - ort.setRelation(SchemaConstants.ORG_DEFAULT); - ort.setType(WebComponentUtil.classToQName(getPageBase().getPrismContext(), object.getClass())); - - -PrismContainerValue newAssignment = getModelObject().getItem().createNewValue(); -newAssignment.asContainerable().setTargetRef(ort); - - -// AssignmentType assignment = new AssignmentType(); -// assignment.setTargetRef(ort); -// assignment.asPrismContainerValue().setParent(getModelObject().getItem()); - - ContainerValueWrapper valueWrapper = factory.createContainerValueWrapper(getModelObject(), newAssignment, - ValueStatus.ADDED, new ItemPath(FocusType.F_ASSIGNMENT)); - getModelObject().getValues().add(valueWrapper); + PrismContainerValue newAssignment = getModelObject().getItem().createNewValue(); + ObjectReferenceType ref = ObjectTypeUtil.createObjectRef(object, relation); + AssignmentType assignmentType = newAssignment.asContainerable(); + if (ResourceType.class.equals(object.getClass())) { + ConstructionType constructionType = new ConstructionType(); + constructionType.setResourceRef(ref); + assignmentType.setConstruction(constructionType); + } else { + assignmentType.setTargetRef(ref); + } + ContainerValueWrapper newAssignmentValueWrapper = createNewAssignmentContainerValueWrapper(newAssignment); +// getModelObject().getValues().add(newAssignmentValueWrapper); + +// ContainerValueWrapper valueWrapper = factory.createContainerValueWrapper(getModelObject(), newAssignment.asPrismContainerValue(), +// ValueStatus.ADDED, new ItemPath(FocusType.F_ASSIGNMENT)); +// getModelObject().getValues().add(valueWrapper); } refreshTable(target); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentPanel.java index 6573ccaafd7..a58e7bf2db2 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentPanel.java @@ -24,6 +24,7 @@ import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.web.component.prism.*; import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import org.apache.commons.lang.StringUtils; import org.apache.wicket.AttributeModifier; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -47,6 +48,7 @@ import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.prism.query.ObjectPaging; import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.web.component.AjaxButton; import com.evolveum.midpoint.web.component.AjaxIconButton; @@ -66,6 +68,7 @@ import com.evolveum.midpoint.web.session.UserProfileStorage.TableId; import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; import javax.xml.datatype.XMLGregorianCalendar; @@ -275,6 +278,7 @@ public void onClick(AjaxRequestTarget target, IModel>> item, String componentId, final IModel> rowModel) { + List assignmentItems = rowModel.getObject().getItems();//ContainerValue().findContainer(AssignmentType.F_ACTIVATION); ItemWrapper activationItem = null; for (ItemWrapper wrapper : assignmentItems){ @@ -323,7 +327,7 @@ public void populateItem(Item, String>> initColumns(); protected abstract void newAssignmentClickPerformed(AjaxRequestTarget target); - + protected void initCustomLayout(WebMarkupContainer assignmentsContainer) { } @@ -349,7 +353,7 @@ public boolean isVisible() { @Override public List> getObject() { - return getAssignmentListProvider().getSelectedData(); + return getModelObject().getValues().stream().filter(v -> v.isSelected()).collect(Collectors.toList()); } }; @@ -377,10 +381,11 @@ protected void populateItem(ListItem> item private static final long serialVersionUID = 1L; @Override - public void onClick(AjaxRequestTarget ajaxRequestTarget) { + public void onClick(AjaxRequestTarget target) { assignmentDetailsVisible = false; getSelectedAssignments().stream().forEach(a -> a.setSelected(false)); - ajaxRequestTarget.add(AssignmentPanel.this); + refreshTable(target); + target.add(AssignmentPanel.this); } }; details.add(doneButton); @@ -485,13 +490,23 @@ protected void deleteAssignmentPerformed(AjaxRequestTarget target, List assignmentContainerWrapper : getModelObject().getValues()){ - if (toDelete.contains(assignmentContainerWrapper)){ - assignmentContainerWrapper.setStatus(ValueStatus.DELETED); - } - } + toDelete.forEach(value -> value.setStatus(ValueStatus.DELETED)); +// for (ContainerValueWrapper assignmentContainerWrapper : getModelObject().getValues()){ +// if (toDelete.contains(assignmentContainerWrapper)){ +// assignmentContainerWrapper.setStatus(ValueStatus.DELETED); +// } +// } refreshTable(target); } + + protected ContainerValueWrapper createNewAssignmentContainerValueWrapper(PrismContainerValue newAssignment) { + ContainerWrapperFactory factory = new ContainerWrapperFactory(getPageBase()); + ContainerValueWrapper valueWrapper = factory.createContainerValueWrapper(getModelObject(), newAssignment, + ValueStatus.ADDED, new ItemPath(FocusType.F_ASSIGNMENT)); + valueWrapper.setShowEmpty(true, false); + getModelObject().getValues().add(valueWrapper); + return valueWrapper; + } protected WebMarkupContainer getAssignmentContainer() { return (WebMarkupContainer) get(ID_ASSIGNMENTS); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/PolicyRulesPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/PolicyRulesPanel.java index d3c2541d994..481a573211e 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/PolicyRulesPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/PolicyRulesPanel.java @@ -16,12 +16,17 @@ package com.evolveum.midpoint.web.component.assignment; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import com.evolveum.midpoint.gui.api.util.WebComponentUtil; +import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.query.ObjectFilter; +import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.web.component.prism.ContainerValueWrapper; import com.evolveum.midpoint.web.component.prism.ContainerWrapper; +import com.evolveum.midpoint.web.component.prism.ContainerWrapperFactory; import com.evolveum.midpoint.web.component.prism.ValueStatus; import com.evolveum.midpoint.web.page.admin.users.dto.UserDtoStatus; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; @@ -143,29 +148,17 @@ private AssignmentsTabStorage getPolicyRulesTabStorage(){ @Override protected void newAssignmentClickPerformed(AjaxRequestTarget target) { - // TODO Auto-generated method stub - - AssignmentType assignment = new AssignmentType(); - - PolicyRuleType policyRule = new PolicyRuleType(getPageBase().getPrismContext()); - policyRule.setDescription(""); - assignment.setPolicyRule(policyRule); - -// ContainerValueWrapper newAssignmentContainerWrapper = assignmentContainerWrapper.createItem(false); -// newAssignmentContainerWrapper.setStatus(ValueStatus.ADDED); -// newAssignmentContainerWrapper.getContainerValue().getValue().setupContainerValue(assignment.asPrismContainerValue()); -// getModelObject().add(newAssignmentContainerWrapper); - target.add(getAssignmentContainer()); + PrismContainerValue newAssignment = getModelObject().getItem().createNewValue(); + ContainerValueWrapper newAssignmentWrapper = createNewAssignmentContainerValueWrapper(newAssignment); + assignmentDetailsPerformed(target, Arrays.asList(newAssignmentWrapper)); +// refreshTable(target); + } @Override protected ObjectQuery createObjectQuery() { return QueryBuilder.queryFor(AssignmentType.class, getParentPage().getPrismContext()) - .block() - .not() - .item(getModelObject().getItemDefinition(), new ItemPath(AssignmentType.F_POLICY_RULE)) - .isNull() - .endBlock() + .exists(AssignmentType.F_POLICY_RULE) .build(); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/form/ValueChoosePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/form/ValueChoosePanel.java index 513c5979068..586161c2dcb 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/form/ValueChoosePanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/form/ValueChoosePanel.java @@ -147,14 +147,30 @@ protected ObjectQuery createChooseQuery(List values) { // } if (oidList.isEmpty()) { + ObjectFilter customFilter = createCustomFilter(); + if (customFilter != null) { + query.addFilter(customFilter); + return query; + } + return null; + } ObjectFilter oidFilter = InOidFilter.createInOid(oidList); query.setFilter(NotFilter.createNot(oidFilter)); + ObjectFilter customFilter = createCustomFilter(); + if (customFilter != null) { + query.addFilter(customFilter); + } + return query; } + + protected ObjectFilter createCustomFilter() { + return null; + } /** * @return css class for off-setting other values (not first, left to the diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/menu/cog/InlineMenu.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/menu/cog/InlineMenu.java index 12a6f7c41cc..fcacf3b280e 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/menu/cog/InlineMenu.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/menu/cog/InlineMenu.java @@ -81,6 +81,7 @@ public void onClick(AjaxRequestTarget ajaxRequestTarget) { } }; menuItemButton.setOutputMarkupId(true); + menuItemButton.setOutputMarkupPlaceholderTag(true); menuItemButton.add(new AttributeAppender("class", "dropdown-toggle " + getAdditionalButtonClass())); menuItemButton.add(new AttributeAppender("style", getMenuItemButtonStyle())); menuItemContainer.add(menuItemButton); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusAssignmentsTabPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusAssignmentsTabPanel.java index 23eedf63d81..8d21965ede9 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusAssignmentsTabPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusAssignmentsTabPanel.java @@ -25,6 +25,7 @@ import com.evolveum.midpoint.web.component.assignment.AssignmentsUtil; import com.evolveum.midpoint.web.component.form.Form; import com.evolveum.midpoint.web.component.prism.*; +import com.evolveum.midpoint.web.model.ContainerWrapperFromObjectWrapperModel; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.wicket.Component; @@ -66,6 +67,7 @@ private void initLayout() { assignments.setOutputMarkupId(true); add(assignments); + new ContainerWrapperFromObjectWrapperModel<>(getObjectWrapperModel(), new ItemPath(FocusType.F_ASSIGNMENT)); AbstractRoleAssignmentPanel panel = new AbstractRoleAssignmentPanel(ID_ASSIGNMENTS_PANEL, Model.of(assignmentsContainerWrapper)); // new AbstractReadOnlyModel>() { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusProjectionsTabPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusProjectionsTabPanel.java index 13293ebbee1..08794369579 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusProjectionsTabPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusProjectionsTabPanel.java @@ -130,7 +130,10 @@ protected void populateItem(final ListItem> item) packageRef = new PackageResourceReference(ImgResources.class, ImgResources.HDD_PRISM); shadowPanel = new PrismPanel(ID_SHADOW, - new ContainerWrapperListFromObjectWrapperModel(objectWrapperModel, Arrays.asList(new ItemPath(ShadowType.F_ATTRIBUTES), SchemaConstants.PATH_ACTIVATION, SchemaConstants.PATH_PASSWORD)), packageRef, + new ContainerWrapperListFromObjectWrapperModel(objectWrapperModel, + Arrays.asList(new ItemPath(ShadowType.F_ATTRIBUTES), + SchemaConstants.PATH_ACTIVATION, SchemaConstants.PATH_PASSWORD + /*,new ItemPath(ShadowType.F_ASSOCIATION ) */)), packageRef, getMainForm(), null, getPageBase()); } else { shadowPanel = new SimpleErrorPanel(ID_SHADOW, item.getModel()) { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerValuePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerValuePanel.java index 0e56b69318f..66f16c7ba6a 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerValuePanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerValuePanel.java @@ -34,6 +34,8 @@ import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; +import com.evolveum.midpoint.web.page.admin.users.component.AssociationValueChoicePanel; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAssociationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; /** @@ -115,6 +117,7 @@ private void addOrReplaceProperties(IModel item) { + if (item.getModel().getObject() instanceof ContainerWrapper) { PrismContainerPanel containerPanel = new PrismContainerPanel("property", (IModel>) item.getModel(), true, form, isPanaleVisible, pageBase); containerPanel.setOutputMarkupId(true); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerValueWrapper.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerValueWrapper.java index 095c551fe91..872e3f09b64 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerValueWrapper.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerValueWrapper.java @@ -195,12 +195,22 @@ static String getDisplayNameFromItem(Item item) { } public boolean hasChanged() { - for (ItemWrapper item : getItems()) { - if (item.hasChanged()) { + + switch (getStatus()) { + case DELETED : return true; - } + case ADDED: + case NOT_CHANGED: + for (ItemWrapper item : getItems()) { + if (item.hasChanged()) { + return true; + } + } } + + + return false; } @@ -372,7 +382,7 @@ public PrismContainerValue createContainerValueAddDelta() throws SchemaExcept try { newValue.addAllReplaceExisting((Collection) getUpdatedContainerValueItems(containerValue.getPrismContext())); } catch (TunnelException e) { - throw new SchemaException(); + throw new SchemaException(e.getMessage(), e); } return newValue; @@ -413,7 +423,7 @@ public Collection getUpdatedContainerValueItems(PrismContext prismContext) } } catch (SchemaException ex) { - throw new TunnelException("Cannot create add delta for container value: " + containerValue); + throw new TunnelException("Cannot create add delta for container value: " + containerValue, ex); } }); return updatedItems; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerWrapper.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerWrapper.java index ed0c1a80513..fb715a9ccbf 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerWrapper.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerWrapper.java @@ -37,6 +37,7 @@ import com.evolveum.midpoint.prism.PrismPropertyDefinition; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.PrettyPrinter; @@ -63,6 +64,9 @@ public class ContainerWrapper extends PrismWrapper impl private List> values; private boolean readonly; + + //TODO: HACK to have custom filter for association contianer here becasue of creating new association: + private ObjectFilter filter; ContainerWrapper(PrismContainer container, ContainerStatus status, ItemPath path) { Validate.notNull(container, "container must not be null."); @@ -93,13 +97,21 @@ public void revive(PrismContext prismContext) throws SchemaException { } } } + + public ObjectFilter getFilter() { + return filter; + } + + public void setFilter(ObjectFilter filter) { + this.filter = filter; + } @Override public PrismContainerDefinition getItemDefinition() { return container.getDefinition(); } - - public ContainerStatus getStatus() { + + public ContainerStatus getStatus() { return status; } @@ -283,16 +295,16 @@ public boolean isEmpty() { return getItem().isEmpty(); } - public void addValue(boolean showEmpty) { - getValues().add(createItem(showEmpty)); + public void addValue(ContainerValueWrapper newValue) { + getValues().add(newValue); } - public ContainerValueWrapper createItem(boolean showEmpty) { - PrismContainerValue pcv = container.createNewValue(); - ContainerValueWrapper wrapper = new ContainerValueWrapper(this, pcv, ValueStatus.ADDED, pcv.getPath()); - wrapper.setShowEmpty(showEmpty, true); - return wrapper; - } +// public ContainerValueWrapper createItem(boolean showEmpty) { +// PrismContainerValue pcv = container.createNewValue(); +// ContainerValueWrapper wrapper = new ContainerValueWrapper(this, pcv, ValueStatus.ADDED, pcv.getPath()); +// wrapper.setShowEmpty(showEmpty, true); +// return wrapper; +// } public void sort(final PageBase pageBase) { for (ContainerValueWrapper valueWrapper : getValues()) { @@ -345,29 +357,37 @@ public void setStripe(boolean isStripe) { // Does not make much sense, but it is given by the interface } - public PrismContainer createContainerAddDelta() throws SchemaException { + public PrismContainer createContainerAddDelta() throws SchemaException { - PrismContainer containerAdd = container.clone(); + PrismContainer containerAdd = container.clone(); for (ContainerValueWrapper itemWrapper : getValues()) { if (!itemWrapper.hasChanged()) { continue; } + + PrismContainerValue newContainerValue = itemWrapper.createContainerValueAddDelta(); + + if (newContainerValue == null) { + continue; + } + if (itemWrapper.isMain()) { - containerAdd.setValue(itemWrapper.createContainerValueAddDelta()); + containerAdd.setValue(newContainerValue); continue; } - containerAdd.add(itemWrapper.createContainerValueAddDelta()); + + if (containerAdd.isSingleValue()) { + containerAdd.replace(newContainerValue); + } else { + containerAdd.add(newContainerValue); + } } return containerAdd; } public void collectModifications(ObjectDelta delta) throws SchemaException { - if (!hasChanged()) { - return; - } - for (ContainerValueWrapper itemWrapper : getValues()) { if (!itemWrapper.hasChanged()) { continue; @@ -386,7 +406,7 @@ public void collectModifications(ObjectDelta delta) th itemWrapper.collectModifications(delta); break; case DELETED: - delta.addModificationDeleteContainer(itemWrapper.getPath(), itemWrapper.getContainerValue().clone()); + delta.addModificationDeleteContainer(getPath(), itemWrapper.getContainerValue().clone()); break; } } @@ -489,4 +509,10 @@ private boolean emphasizedAndCanAdd(PrismContainerDefinition def) { return def.canAdd() && def.isEmphasized(); } + @Override + public void addValue(boolean showEmpty) { + // TODO Auto-generated method stub + + } + } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerWrapperFactory.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerWrapperFactory.java index 690e758ba6d..a56c379c568 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerWrapperFactory.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerWrapperFactory.java @@ -23,7 +23,11 @@ import com.evolveum.midpoint.gui.api.util.ModelServiceLocator; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.ObjectFilter; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.query.builder.QueryBuilder; import com.evolveum.midpoint.schema.CapabilityUtil; +import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ResourceTypeUtil; import com.evolveum.midpoint.util.DOMUtil; @@ -90,12 +94,11 @@ public ContainerWrapper createContainerWrapper( List> containerValues = createContainerValues(cWrapper, path); cWrapper.setProperties(containerValues); cWrapper.computeStripes(); - - return cWrapper; + + return cWrapper; } - - public ContainerWrapper createContainerWrapper(PrismContainer container, ContainerStatus status, ItemPath path, boolean readonly) { + public ContainerWrapper createContainerWrapper(PrismContainer container, ContainerStatus status, ItemPath path, boolean readonly) { result = new OperationResult(CREATE_PROPERTIES); @@ -113,7 +116,7 @@ private List> createContainer List> containerValueWrappers = new ArrayList<>(); PrismContainer container = cWrapper.getItem(); - if (container.getValues().isEmpty()) { + if (container.getValues().isEmpty() && !(new ItemPath(FocusType.F_ASSIGNMENT)).equivalent(container.getPath())) { PrismContainerValue pcv = container.createNewValue(); ContainerValueWrapper containerValueWrapper = createContainerValueWrapper(cWrapper, pcv, ValueStatus.ADDED, cWrapper.getPath()); @@ -122,7 +125,7 @@ private List> createContainer } container.getValues().forEach(pcv -> { - ContainerValueWrapper containerValueWrapper = createContainerValueWrapper(cWrapper, pcv, ValueStatus.NOT_CHANGED, pcv.getPath()); + ContainerValueWrapper containerValueWrapper = createContainerValueWrapper(cWrapper, pcv, cWrapper.getStatus() == ContainerStatus.ADDING ? ValueStatus.ADDED : ValueStatus.NOT_CHANGED, pcv.getPath()); containerValueWrappers.add(containerValueWrapper); }); @@ -136,6 +139,11 @@ public ContainerValueWrapper createContainerValueWr List properties = createProperties(containerValueWrapper, false); containerValueWrapper.setProperties(properties); + ReferenceWrapper shadowRefWrapper = (ReferenceWrapper) containerValueWrapper.findPropertyWrapper(ShadowAssociationType.F_SHADOW_REF); + if (shadowRefWrapper != null && cWrapper.getFilter() != null) { + shadowRefWrapper.setFilter(cWrapper.getFilter()); + } + return containerValueWrapper; } @@ -241,7 +249,7 @@ private PropertyWrapper createPropertyWrapper( // } return new PropertyWrapper(cWrapper, newProperty, propertyIsReadOnly, ValueStatus.ADDED, cWrapper.getPath().append(newProperty.getPath())); } - return new PropertyWrapper(cWrapper, property, propertyIsReadOnly, ValueStatus.NOT_CHANGED, property.getPath()); + return new PropertyWrapper(cWrapper, property, propertyIsReadOnly, cWrapper.getStatus() == ValueStatus.ADDED ? ValueStatus.ADDED: ValueStatus.NOT_CHANGED, property.getPath()); } private ReferenceWrapper createReferenceWrapper(PrismReferenceDefinition def, ContainerValueWrapper cWrapper, boolean onlyEmpty) { @@ -268,7 +276,7 @@ private ReferenceWrapper createReferenceWrapper(PrismR } return new ReferenceWrapper(cWrapper, reference, propertyIsReadOnly, - ValueStatus.NOT_CHANGED, reference.getPath()); + cWrapper.getStatus() == ValueStatus.ADDED ? ValueStatus.ADDED: ValueStatus.NOT_CHANGED, reference.getPath()); } @@ -299,7 +307,7 @@ private ContainerWrapper createContainerWrapper(Pri } return createContainerWrapper(newContainer, ContainerStatus.ADDING, cWrapper.getPath().append(newContainer.getPath())); } - return createContainerWrapper(container, ContainerStatus.MODIFYING, container.getPath()); + return createContainerWrapper(container, cWrapper.getStatus() == ValueStatus.ADDED ? ContainerStatus.ADDING: ContainerStatus.MODIFYING, container.getPath()); } private ContainerWrapper createPolicyConstraintsContainer(PrismContainer policyConstraintsContainer, PrismContainerDefinition def, ContainerValueWrapper parentContainer) { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapper.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapper.java index 375b8f99053..2951946c6d7 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapper.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapper.java @@ -343,8 +343,8 @@ public ObjectDelta getObjectDelta() throws SchemaException { for (ContainerWrapper containerWrapper : getContainers()) { containerWrapper.collectModifications(delta); - containerWrapper.collectDeleteDelta(delta, object.getPrismContext()); - containerWrapper.collectAddDelta(delta, object.getPrismContext()); +// containerWrapper.collectDeleteDelta(delta, object.getPrismContext()); +// containerWrapper.collectAddDelta(delta, object.getPrismContext()); } // returning container to previous order Collections.sort(containers, new ItemWrapperComparator()); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapperFactory.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapperFactory.java index 56d63c6b3fe..5a528470d66 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapperFactory.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapperFactory.java @@ -16,13 +16,22 @@ package com.evolveum.midpoint.web.component.prism; +import com.evolveum.midpoint.common.refinery.CompositeRefinedObjectClassDefinition; +import com.evolveum.midpoint.common.refinery.RefinedAssociationDefinition; import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; +import com.evolveum.midpoint.common.refinery.RefinedResourceSchema; +import com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl; import com.evolveum.midpoint.gui.api.util.ModelServiceLocator; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.path.ItemPathSegment; import com.evolveum.midpoint.prism.path.NameItemPathSegment; +import com.evolveum.midpoint.prism.query.ObjectFilter; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.query.OrFilter; +import com.evolveum.midpoint.prism.query.builder.QueryBuilder; import com.evolveum.midpoint.prism.schema.PrismSchema; +import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ConnectorTypeUtil; import com.evolveum.midpoint.schema.util.ReportTypeUtil; @@ -226,53 +235,147 @@ private List> c return list; } - private void addContainerWrappers( - List> containerWrappers, - ObjectWrapper oWrapper, PrismContainer parentContainer, ItemPath path, - OperationResult result) throws SchemaException { + private void addContainerWrappers( + List> containerWrappers, ObjectWrapper oWrapper, + PrismContainer parentContainer, ItemPath path, OperationResult result) throws SchemaException { - PrismContainerDefinition parentContainerDefinition = parentContainer.getDefinition(); - - List segments = new ArrayList<>(); - if (path != null) { - segments.addAll(path.getSegments()); - } - ItemPath parentPath = new ItemPath(segments); - for (ItemDefinition def : (Collection) parentContainerDefinition.getDefinitions()) { - if (!(def instanceof PrismContainerDefinition)) { - continue; - } - if (isIgnoreContainer(def.getTypeName())) { - continue; - } - - LOGGER.trace("ObjectWrapper.createContainerWrapper processing definition: {}", def); - - PrismContainerDefinition containerDef = (PrismContainerDefinition) def; - - ItemPath newPath = createPropertyPath(parentPath, containerDef.getName()); - - ContainerWrapperFactory cwf = new ContainerWrapperFactory(modelServiceLocator); - - if (AssignmentType.COMPLEX_TYPE.equals(parentContainer.getDefinition().getName())) { - System.out.println("something"); - } - - PrismContainer prismContainer = parentContainer.findContainer(def.getName()); - - ContainerWrapper container; - if (prismContainer != null) { - container = cwf.createContainerWrapper(prismContainer, ContainerStatus.MODIFYING, newPath); - } else { - prismContainer = containerDef.instantiate(); - container = cwf.createContainerWrapper(prismContainer, ContainerStatus.ADDING, newPath); - } - result.addSubresult(cwf.getResult()); - containerWrappers.add(container); - - } - } + PrismContainerDefinition parentContainerDefinition = parentContainer.getDefinition(); + List segments = new ArrayList<>(); + if (path != null) { + segments.addAll(path.getSegments()); + } + ItemPath parentPath = new ItemPath(segments); + for (ItemDefinition def : (Collection) parentContainerDefinition.getDefinitions()) { + if (!(def instanceof PrismContainerDefinition)) { + continue; + } + if (isIgnoreContainer(def.getTypeName())) { + continue; + } + + LOGGER.trace("ObjectWrapper.createContainerWrapper processing definition: {}", def); + + PrismContainerDefinition containerDef = (PrismContainerDefinition) def; + + ItemPath newPath = createPropertyPath(parentPath, containerDef.getName()); + + ContainerWrapperFactory cwf = new ContainerWrapperFactory(modelServiceLocator); + + if (AssignmentType.COMPLEX_TYPE.equals(parentContainer.getDefinition().getName())) { + System.out.println("something"); + } + + PrismContainer prismContainer = parentContainer.findContainer(def.getName()); + + ContainerWrapper container; + if (prismContainer != null) { + container = cwf.createContainerWrapper(prismContainer, ContainerStatus.MODIFYING, newPath); + } else { + prismContainer = containerDef.instantiate(); + container = cwf.createContainerWrapper(prismContainer, ContainerStatus.ADDING, newPath); + } + + if (SchemaConstants.PATH_ASSOCIATION.equivalent(newPath)) { + ObjectFilter filter = getAssociationsSearchFilter((PrismObject) oWrapper.getObject()); + + container.setFilter(filter); + + container.getValues().forEach(containerValueWrapper -> { + ReferenceWrapper shadowRefWrapper = (ReferenceWrapper) containerValueWrapper.findPropertyWrapper(ShadowAssociationType.F_SHADOW_REF); + if (shadowRefWrapper != null) { + shadowRefWrapper.setFilter(filter); + } + }); + + } + + result.addSubresult(cwf.getResult()); + containerWrappers.add(container); + + } + } + + private ObjectFilter getAssociationsSearchFilter(PrismObject shadow) { + + Map> assocMap = new HashMap<>(); + PrismContainer associationContainer = shadow.findContainer(ShadowType.F_ASSOCIATION); + if (associationContainer != null && associationContainer.getValues() != null) { + // Do NOT load shadows here. This will be huge overhead if there are many associations. + // Load them on-demand (if necessary at all). + List> associations = associationContainer.getValues(); + if (associations != null) { + for (PrismContainerValue cval : associations) { + ShadowAssociationType associationType = cval.asContainerable(); + QName assocName = associationType.getName(); + PrismContainer fractionalContainer = assocMap.get(assocName); + if (fractionalContainer == null) { + fractionalContainer = new PrismContainer<>(ShadowType.F_ASSOCIATION, ShadowAssociationType.class, cval.getPrismContext()); + fractionalContainer.setDefinition(cval.getParent().getDefinition()); + // HACK: set the name of the association as the element name so wrapper.getName() will return correct data. + fractionalContainer.setElementName(assocName); + assocMap.put(assocName, fractionalContainer); + } + try { + fractionalContainer.add(cval.clone()); + } catch (SchemaException e) { + // Should not happen + throw new SystemException("Unexpected error: " + e.getMessage(), e); + } + } + } + } + + PrismReference resourceRef = shadow.findReference(ShadowType.F_RESOURCE_REF); + PrismObject resource = resourceRef.getValue().getObject(); + + // HACK. The revive should not be here. Revive is no good. The next use of the resource will + // cause parsing of resource schema. We need some centralized place to maintain live cached copies + // of resources. + try { + resource.revive(modelServiceLocator.getPrismContext()); + } catch (SchemaException e) { + throw new SystemException(e.getMessage(), e); + } + RefinedResourceSchema refinedSchema; + CompositeRefinedObjectClassDefinition rOcDef; + try { + refinedSchema = RefinedResourceSchemaImpl.getRefinedSchema(resource); + rOcDef = refinedSchema.determineCompositeObjectClassDefinition(shadow); + } catch (SchemaException e) { + throw new SystemException(e.getMessage(), e); + } + // Make sure even empty associations have their wrappers so they can be displayed and edited +// for (RefinedAssociationDefinition assocDef : rOcDef.getAssociationDefinitions()) { +// QName name = assocDef.getName(); +// if (!assocMap.containsKey(name)) { +// PrismContainer fractionalContainer = new PrismContainer<>(ShadowType.F_ASSOCIATION, ShadowAssociationType.class, prismContext); +// fractionalContainer.setDefinition(cWrapper.getItemDefinition()); +// // HACK: set the name of the association as the element name so wrapper.getName() will return correct data. +// fractionalContainer.setElementName(name); +// assocMap.put(name, fractionalContainer); +// } +// } + + List associatonFilters = new ArrayList<>(); + + ShadowType shadowType = shadow.asObjectable(); + rOcDef.getAssociationDefinitions().forEach(def -> { + RefinedObjectClassDefinition assocDef = def.getAssociationTarget(); + associatonFilters.add(createAssociationFilter(shadowType.getResourceRef().getOid(), assocDef.getKind(), assocDef.getObjectClassDefinition().getTypeName())); + }); + + return OrFilter.createOr(associatonFilters); + + } + + private ObjectFilter createAssociationFilter(String resourceOid, ShadowKindType kind, QName objectClass) { + return QueryBuilder.queryFor(ShadowType.class, modelServiceLocator.getPrismContext()) + .item(ShadowType.F_OBJECT_CLASS).eq(objectClass) + .and().item(ShadowType.F_KIND).eq(kind) + .and().item(ShadowType.F_RESOURCE_REF).ref(resourceOid) + .buildFilter(); + } private boolean isIgnoreContainer(QName containerDefinitionName) { for (QName container : CONTAINERS_TO_IGNORE) { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismContainerHeaderPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismContainerHeaderPanel.java index d9c7f31dbbd..66208d32fd8 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismContainerHeaderPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismContainerHeaderPanel.java @@ -45,7 +45,11 @@ public void onClick(AjaxRequestTarget target) { } private void addValue(AjaxRequestTarget target) { - getModelObject().addValue(true); + ContainerWrapperFactory cwf = new ContainerWrapperFactory(getPageBase()); + ContainerWrapper containerWrapper = getModelObject(); + ContainerValueWrapper newContainerValue = cwf.createContainerValueWrapper(containerWrapper, containerWrapper.getItem().createNewValue(), ValueStatus.ADDED, containerWrapper.getPath()); + newContainerValue.setShowEmpty(true, false); + getModelObject().addValue(newContainerValue); onButtonClick(target); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismValuePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismValuePanel.java index 0d156a7f41e..40be30a3ce7 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismValuePanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismValuePanel.java @@ -660,7 +660,17 @@ protected void updateFeedbackPanel(AutoCompleteTextField input, boolean isError, } panel = new ValueChoosePanel(id, - new PropertyModel<>(valueWrapperModel, "value"), item.getValues(), false, typeClasses); + new PropertyModel<>(valueWrapperModel, "value"), item.getValues(), false, typeClasses) { + + @Override + protected ObjectFilter createCustomFilter() { + ItemWrapper wrapper = valueWrapperModel.getObject().getItem(); + if (!(wrapper instanceof ReferenceWrapper)){ + return null; + } + return ((ReferenceWrapper) wrapper).getFilter(); + } + }; } else if (item instanceof PrismContainer) { // AssociationWrapper itemWrapper = (AssociationWrapper) valueWrapperModel.getObject().getItem(); @@ -857,12 +867,12 @@ private void removeValue(AjaxRequestTarget target) { target.add(parent.getParent()); } - private ObjectQuery getAssociationsSearchQuery(PrismContext prismContext, PrismObject resource, QName objectClass, ShadowKindType kind) { - return QueryBuilder.queryFor(ShadowType.class, prismContext) - .item(ShadowType.F_OBJECT_CLASS).eq(objectClass) - .and().item(ShadowType.F_KIND).eq(kind) - .and().item(ShadowType.F_RESOURCE_REF).ref(resource.getOid()) - .build(); - } +// private ObjectQuery getAssociationsSearchQuery(PrismContext prismContext, PrismObject resource, QName objectClass, ShadowKindType kind) { +// return QueryBuilder.queryFor(ShadowType.class, prismContext) +// .item(ShadowType.F_OBJECT_CLASS).eq(objectClass) +// .and().item(ShadowType.F_KIND).eq(kind) +// .and().item(ShadowType.F_RESOURCE_REF).ref(resource.getOid()) +// .build(); +// } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ReferenceWrapper.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ReferenceWrapper.java index 474d490d678..521828a7189 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ReferenceWrapper.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ReferenceWrapper.java @@ -19,6 +19,7 @@ import com.evolveum.midpoint.prism.PrismReferenceDefinition; import com.evolveum.midpoint.prism.PrismReferenceValue; import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.PrettyPrinter; @@ -29,6 +30,8 @@ public class ReferenceWrapper extends PropertyOrReferenceWrapper implements Serializable { private static final long serialVersionUID = 3132143219403214903L; + + private ObjectFilter filter; public ReferenceWrapper(ContainerValueWrapper container, PrismReference reference, boolean readonly, ValueStatus status) { super(container, reference, readonly, status, null); @@ -49,7 +52,8 @@ private List createValues() { List values = new ArrayList(); for (PrismReferenceValue prismValue : item.getValues()) { - values.add(new ValueWrapper(this, prismValue, prismValue, ValueStatus.NOT_CHANGED)); + + values.add(new ValueWrapper(this, prismValue, ValueStatus.NOT_CHANGED)); } int minOccurs = getItemDefinition().getMinOccurs(); @@ -70,6 +74,14 @@ public ValueWrapper createAddedValue() { ValueWrapper wrapper = new ValueWrapper(this, prv, ValueStatus.ADDED); return wrapper; } + + public ObjectFilter getFilter() { + return filter; + } + + public void setFilter(ObjectFilter filter) { + this.filter = filter; + } @Override public String toString() { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ValueWrapper.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ValueWrapper.java index 5ede2841065..7c7ecb2aa9f 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ValueWrapper.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ValueWrapper.java @@ -41,22 +41,22 @@ public class ValueWrapper implements Serializable, DebugDumpable { private static final Trace LOGGER = TraceManager.getTrace(ValueWrapper.class); - private ItemWrapper item; + private PropertyOrReferenceWrapper item; private PrismValue value; private PrismValue oldValue; // private PrismPropertyValue value; // private PrismPropertyValue oldValue; private ValueStatus status; - public ValueWrapper(ItemWrapper property, PrismValue value) { + public ValueWrapper(PropertyOrReferenceWrapper property, PrismValue value) { this(property, value, ValueStatus.NOT_CHANGED); } - public ValueWrapper(ItemWrapper property, PrismValue value, ValueStatus status) { + public ValueWrapper(PropertyOrReferenceWrapper property, PrismValue value, ValueStatus status) { this(property, value, null, status); } - public ValueWrapper(ItemWrapper property, PrismValue value, PrismValue oldValue, + public ValueWrapper(PropertyOrReferenceWrapper property, PrismValue value, PrismValue oldValue, ValueStatus status) { Validate.notNull(property, "Property wrapper must not be null."); Validate.notNull(value, "Property value must not be null."); @@ -87,7 +87,19 @@ public ValueWrapper(ItemWrapper property, PrismValue value, PrismValue oldValue, } } - if (oldValue == null && value instanceof PrismPropertyValue) { + if (oldValue == null && value instanceof PrismPropertyValue && ValueStatus.ADDED == property.getStatus()) { + oldValue = new PrismPropertyValue(null); + } + + if (oldValue == null && value instanceof PrismReferenceValue && ValueStatus.ADDED == property.getStatus()) { + oldValue = new PrismReferenceValue(); + } + + if (oldValue == null && value instanceof PrismReferenceValue && ValueStatus.ADDED != property.getStatus()) { + oldValue = value.clone(); + } + + if (oldValue == null && value instanceof PrismPropertyValue && ValueStatus.ADDED != property.getStatus()) { T val = ((PrismPropertyValue) this.value).getValue(); if (val instanceof PolyString) { PolyString poly = (PolyString)val; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/content/PageAccount.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/content/PageAccount.java index 9b950080189..c9db0419fd7 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/content/PageAccount.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/content/PageAccount.java @@ -150,7 +150,9 @@ public boolean isVisible() { } private List getItemsToShow() { - return Arrays.asList(new ItemPath(ShadowType.F_ATTRIBUTES), SchemaConstants.PATH_ACTIVATION, SchemaConstants.PATH_PASSWORD); + return Arrays.asList(new ItemPath(ShadowType.F_ATTRIBUTES), + SchemaConstants.PATH_ACTIVATION, SchemaConstants.PATH_PASSWORD, + new ItemPath(ShadowType.F_ASSOCIATION)); } private void initButtons(Form mainForm) { diff --git a/gui/admin-gui/src/main/resources/initial-objects/010-value-policy.xml b/gui/admin-gui/src/main/resources/initial-objects/010-value-policy.xml index 0ed12a8d0f0..773af1fbcd8 100644 --- a/gui/admin-gui/src/main/resources/initial-objects/010-value-policy.xml +++ b/gui/admin-gui/src/main/resources/initial-objects/010-value-policy.xml @@ -23,13 +23,6 @@ default password policy Default password policy - - 999 - 9 - 0 - 0 - 0 - Testing string policy diff --git a/gui/admin-gui/src/main/resources/initial-objects/040-role-enduser.xml b/gui/admin-gui/src/main/resources/initial-objects/040-role-enduser.xml index a58f82ce2d9..d8b69d15f80 100644 --- a/gui/admin-gui/src/main/resources/initial-objects/040-role-enduser.xml +++ b/gui/admin-gui/src/main/resources/initial-objects/040-role-enduser.xml @@ -131,8 +131,6 @@ credentials assignment - parentOrgRef - roleMembershipRef self-shadow-execution-add-modify-delete diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/ExistsFilter.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/ExistsFilter.java index 8e855bac0f1..d843609f615 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/ExistsFilter.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/ExistsFilter.java @@ -87,7 +87,7 @@ public ExistsFilter cloneEmpty() { @Override public boolean match(PrismContainerValue value, MatchingRuleRegistry matchingRuleRegistry) throws SchemaException { Item itemToFind = value.findItem(fullPath); - if (itemToFind == null || itemToFind.isEmpty()) { + if (itemToFind == null || itemToFind.getValues().isEmpty()) { return false; } if (!(itemToFind instanceof PrismContainer)) { diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/SchemaDebugUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/SchemaDebugUtil.java index 39eb96a8cf8..27dbe156f3a 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/SchemaDebugUtil.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/SchemaDebugUtil.java @@ -50,7 +50,9 @@ import com.evolveum.midpoint.xml.ns._public.common.api_types_3.PropertyReferenceListType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CachingMetadataType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ConstExpressionEvaluatorType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConstructionType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectDeltaOperationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; @@ -318,6 +320,59 @@ public static String prettyPrint(ResourceAttributeDefinitionType vc) { sb.append(")"); return sb.toString(); } + + public static String prettyPrint(ExpressionType expressionType) { + if (expressionType == null) { + return "null"; + } + StringBuilder sb = new StringBuilder("ExpressionType("); + appendPropertyIfNotNull(sb, "description", expressionType.getDescription()); + appendPropertyIfNotNull(sb, "extension", expressionType.getExtension()); + appendPropertyIfNotNull(sb, "trace", expressionType.isTrace()); + appendPropertyIfNotNull(sb, "variable", expressionType.getVariable()); + appendPropertyIfNotNull(sb, "returnMultiplicity", expressionType.getReturnMultiplicity()); + appendPropertyIfNotNull(sb, "allowEmptyValues", expressionType.isAllowEmptyValues()); + appendPropertyIfNotNull(sb, "queryInterpretationOfNoValue", expressionType.getQueryInterpretationOfNoValue()); + appendPropertyIfNotNull(sb, "runAsRef", expressionType.getRunAsRef()); + List> expressionEvaluators = expressionType.getExpressionEvaluator(); + sb.append("evaluator").append("="); + if (expressionEvaluators.isEmpty()) { + sb.append("[]"); + } else { + if (expressionEvaluators.size() > 1) { + sb.append("["); + } + for (JAXBElement expressionEvaluator : expressionEvaluators) { + sb.append(expressionEvaluator.getName().getLocalPart()); + sb.append(":"); + sb.append(PrettyPrinter.prettyPrint(expressionEvaluator.getValue())); + if (expressionEvaluators.size() > 1) { + sb.append(", "); + } + } + if (expressionEvaluators.size() > 1) { + sb.append("]"); + } + } + sb.append(")"); + return sb.toString(); + } + + public static String prettyPrint(ConstExpressionEvaluatorType expressionType) { + if (expressionType == null) { + return "null"; + } + StringBuilder sb = new StringBuilder("ConstExpressionEvaluatorType("); + sb.append(expressionType.getValue()); + sb.append(")"); + return sb.toString(); + } + + private static void appendPropertyIfNotNull(StringBuilder sb, String propName, Object value) { + if (value != null) { + sb.append(propName).append("=").append(value).append(","); + } + } public static String prettyPrint(CachingMetadataType cachingMetadata) { if (cachingMetadata == null) { diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd index e6f6d19fef8..ec183cbcc60 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd @@ -9507,6 +9507,20 @@ + + + + If set to false (defaul) the specification will apply only to active relations + (e.g active delegations). If set to true then the specificaiton will also be applied + to inactive relations (e.g. expired delegations). + Only partially implemented. Works only for some cases (delegator). + EXPERIMENTAL. Use at your own risk. + + + 3.6.1 + + + diff --git a/infra/util/src/main/java/com/evolveum/midpoint/util/DebugUtil.java b/infra/util/src/main/java/com/evolveum/midpoint/util/DebugUtil.java index 1eec6d4f366..fc82041efa8 100644 --- a/infra/util/src/main/java/com/evolveum/midpoint/util/DebugUtil.java +++ b/infra/util/src/main/java/com/evolveum/midpoint/util/DebugUtil.java @@ -191,7 +191,7 @@ public static String debugDump(Object object, int indent) { } else { StringBuilder sb = new StringBuilder(); indentDebugDump(sb, indent + 1); - sb.append(object.toString()); + sb.append(PrettyPrinter.prettyPrint(object)); return sb.toString(); } } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/AbstractSecurityTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/AbstractSecurityTest.java index 5700889f2d7..8deafa43f1f 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/AbstractSecurityTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/AbstractSecurityTest.java @@ -27,8 +27,10 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.function.Predicate; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; @@ -71,6 +73,8 @@ import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.test.util.TestUtil; +import com.evolveum.midpoint.util.FailableProcessor; +import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; @@ -81,11 +85,13 @@ import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCampaignType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCaseType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentPolicyEnforcementType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationDecisionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OwnedObjectSelectorType; import com.evolveum.midpoint.xml.ns._public.common.common_3.PartialProcessingOptionsType; @@ -97,6 +103,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.SubjectedObjectSelectorType; import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; /** * @author semancik @@ -220,6 +227,9 @@ public abstract class AbstractSecurityTest extends AbstractInitializedModelInteg protected static final File ROLE_DELEGATOR_FILE = new File(TEST_DIR, "role-delegator.xml"); protected static final String ROLE_DELEGATOR_OID = "00000000-0000-0000-0000-00000000d001"; + + protected static final File ROLE_DELEGATOR_PLUS_FILE = new File(TEST_DIR, "role-delegator-plus.xml"); + protected static final String ROLE_DELEGATOR_PLUS_OID = "00000000-0000-0000-0000-00000000d101"; protected static final File ROLE_ORG_READ_ORGS_MINISTRY_OF_RUM_FILE = new File(TEST_DIR, "role-org-read-orgs-ministry-of-rum.xml"); protected static final String ROLE_ORG_READ_ORGS_MINISTRY_OF_RUM_OID = "00000000-0000-0000-0000-00000000aa0d"; @@ -349,7 +359,7 @@ public abstract class AbstractSecurityTest extends AbstractInitializedModelInteg protected static final XMLGregorianCalendar JACK_VALID_FROM_LONG_AGO = XmlTypeConverter.createXMLGregorianCalendar(10000L); protected static final int NUMBER_OF_ALL_USERS = 11; - protected static final int NUMBER_OF_IMPORTED_ROLES = 63; + protected static final int NUMBER_OF_IMPORTED_ROLES = 64; protected static final int NUMBER_OF_ALL_ORGS = 11; protected String userRumRogersOid; @@ -393,6 +403,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti repoAddObjectFromFile(ROLE_ASSIGN_REQUESTABLE_ROLES_FILE, initResult); repoAddObjectFromFile(ROLE_ASSIGN_ORGRELATION_FILE, initResult); repoAddObjectFromFile(ROLE_DELEGATOR_FILE, initResult); + repoAddObjectFromFile(ROLE_DELEGATOR_PLUS_FILE, initResult); repoAddObjectFromFile(ROLE_ORG_READ_ORGS_MINISTRY_OF_RUM_FILE, initResult); repoAddObjectFromFile(ROLE_FILTER_OBJECT_USER_LOCATION_SHADOWS_FILE, initResult); repoAddObjectFromFile(ROLE_FILTER_OBJECT_USER_TYPE_SHADOWS_FILE, initResult); @@ -559,8 +570,11 @@ protected void assertAttributeFlags(RefinedObjectClassDefinition rOcDef, QName a assertEquals("Wrong modification flag for "+attrName, expectedModify, rAttrDef.canModify()); } - protected void cleanupAutzTest(String userOid) throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, ObjectAlreadyExistsException, PolicyViolationException, SecurityViolationException, IOException { + cleanupAutzTest(userOid, 0); + } + + protected void cleanupAutzTest(String userOid, int expectedAssignments) throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, ObjectAlreadyExistsException, PolicyViolationException, SecurityViolationException, IOException { login(userAdministrator); if (userOid != null) { unassignAllRoles(userOid); @@ -568,6 +582,8 @@ protected void cleanupAutzTest(String userOid) throws ObjectNotFoundException, S Task task = taskManager.createTaskInstance(AbstractSecurityTest.class.getName() + ".cleanupAutzTest"); OperationResult result = task.getResult(); + + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.FULL); cleanupDelete(UserType.class, USER_HERMAN_OID, task, result); cleanupDelete(UserType.class, USER_DRAKE_OID, task, result); @@ -584,6 +600,7 @@ protected void cleanupAutzTest(String userOid) throws ObjectNotFoundException, S modifyUserReplace(USER_JACK_OID, SchemaConstants.PATH_ACTIVATION_VALID_FROM, task, result); modifyUserReplace(USER_JACK_OID, UserType.F_GIVEN_NAME, task, result, createPolyString(USER_JACK_GIVEN_NAME)); + unassignAccount(USER_JACK_OID, RESOURCE_DUMMY_OID, null); unassignOrg(USER_JACK_OID, ORG_MINISTRY_OF_RUM_OID, SchemaConstants.ORG_MANAGER, task, result); unassignOrg(USER_JACK_OID, ORG_MINISTRY_OF_RUM_OID, null, task, result); unassignOrg(USER_JACK_OID, ORG_MINISTRY_OF_DEFENSE_OID, SchemaConstants.ORG_MANAGER, task, result); @@ -595,6 +612,14 @@ protected void cleanupAutzTest(String userOid) throws ObjectNotFoundException, S cleanupDelete(TaskType.class, TASK_T4_OID, task, result); cleanupDelete(TaskType.class, TASK_T5_OID, task, result); cleanupDelete(TaskType.class, TASK_T6_OID, task, result); + + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + PrismObject user = getUser(userOid); + assertAssignments(user, expectedAssignments); + if (expectedAssignments == 0) { + assertLinks(user, 0); + } } protected void cleanupAdd(File userLargoFile, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException, IOException { @@ -615,12 +640,12 @@ protected void cleanupDelete(Class type, String oid, T } } - protected void assertVisibleUsers(int expectedNumAllUsers) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + protected void assertVisibleUsers(int expectedNumAllUsers) throws Exception { assertSearch(UserType.class, null, expectedNumAllUsers); } - protected void assertReadDeny() throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + protected void assertReadDeny() throws Exception { assertReadDeny(0); assertReadDenyRaw(); } @@ -637,7 +662,7 @@ protected void assertReadCertCases(int expectedNumber) throws ObjectNotFoundExce assertContainerSearch(AccessCertificationCaseType.class, null, expectedNumber); } - protected void assertReadDeny(int expectedNumAllUsers) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + protected void assertReadDeny(int expectedNumAllUsers) throws Exception { assertGetDeny(UserType.class, USER_JACK_OID); assertGetDeny(UserType.class, USER_JACK_OID, SelectorOptions.createCollection(GetOperationOptions.createRaw())); assertGetDeny(UserType.class, USER_GUYBRUSH_OID); @@ -650,7 +675,7 @@ protected void assertReadDeny(int expectedNumAllUsers) throws ObjectNotFoundExce assertSearch(UserType.class, createNameQuery(USER_GUYBRUSH_USERNAME), SelectorOptions.createCollection(GetOperationOptions.createRaw()), 0); } - protected void assertReadDenyRaw() throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + protected void assertReadDenyRaw() throws Exception { assertGetDeny(UserType.class, USER_JACK_OID, SelectorOptions.createCollection(GetOperationOptions.createRaw())); assertGetDeny(UserType.class, USER_GUYBRUSH_OID, SelectorOptions.createCollection(GetOperationOptions.createRaw())); @@ -659,11 +684,11 @@ protected void assertReadDenyRaw() throws ObjectNotFoundException, SchemaExcepti assertSearchDeny(UserType.class, createNameQuery(USER_GUYBRUSH_USERNAME), SelectorOptions.createCollection(GetOperationOptions.createRaw())); } - protected void assertReadAllow() throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + protected void assertReadAllow() throws Exception { assertReadAllow(NUMBER_OF_ALL_USERS); } - protected void assertReadAllow(int expectedNumAllUsers) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + protected void assertReadAllow(int expectedNumAllUsers) throws Exception { assertGetAllow(UserType.class, USER_JACK_OID); assertGetAllow(UserType.class, USER_GUYBRUSH_OID); @@ -672,11 +697,11 @@ protected void assertReadAllow(int expectedNumAllUsers) throws ObjectNotFoundExc assertSearch(UserType.class, createNameQuery(USER_GUYBRUSH_USERNAME), 1); } - protected void assertReadAllowRaw() throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + protected void assertReadAllowRaw() throws Exception { assertReadAllowRaw(NUMBER_OF_ALL_USERS); } - protected void assertReadAllowRaw(int expectedNumAllUsers) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + protected void assertReadAllowRaw(int expectedNumAllUsers) throws Exception { assertGetAllow(UserType.class, USER_JACK_OID, SelectorOptions.createCollection(GetOperationOptions.createRaw())); assertGetAllow(UserType.class, USER_GUYBRUSH_OID, SelectorOptions.createCollection(GetOperationOptions.createRaw())); @@ -773,11 +798,11 @@ protected PrismObject assertGetAllow(Class type, St return object; } - protected void assertSearch(Class type, ObjectQuery query, int expectedResults) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + protected void assertSearch(Class type, ObjectQuery query, int expectedResults) throws Exception { assertSearch(type, query, null, expectedResults); } - protected void assertSearchRaw(Class type, ObjectQuery query, int expectedResults) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + protected void assertSearchRaw(Class type, ObjectQuery query, int expectedResults) throws Exception { assertSearch(type, query, SelectorOptions.createCollection(GetOperationOptions.createRaw()), expectedResults); } @@ -786,7 +811,7 @@ protected void assertContainerSearch(Class type, Ob } protected void assertSearchDeny(Class type, ObjectQuery query, - Collection> options) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + Collection> options) throws Exception { try { assertSearch(type, query, options, 0); } catch (SecurityViolationException e) { @@ -795,21 +820,70 @@ protected void assertSearchDeny(Class type, ObjectQuer } } + + protected void assertSearch(Class type, ObjectQuery query, + Collection> options, int expectedResults) throws Exception { + assertSearch(type, query, options, + new SearchAssertion() { + + @Override + public void assertObjects(String message, List> objects) throws Exception { + if (objects.size() > expectedResults) { + failDeny(message, type, query, expectedResults, objects.size()); + } else if (objects.size() < expectedResults) { + failAllow(message, type, query, expectedResults, objects.size()); + } + } + + @Override + public void assertCount(int count) throws Exception { + if (count > expectedResults) { + failDeny("count", type, query, expectedResults, count); + } else if (count < expectedResults) { + failAllow("count", type, query, expectedResults, count); + } + } + + }); + } + + protected void assertSearch(Class type, ObjectQuery query, String... expectedOids) throws Exception { + assertSearch(type, query, null, expectedOids); + } + + protected void assertSearch(Class type, ObjectQuery query, + Collection> options, String... expectedOids) throws Exception { + assertSearch(type, query, options, + new SearchAssertion() { + + @Override + public void assertObjects(String message, List> objects) throws Exception { + if (!MiscUtil.unorderedCollectionEquals(objects, Arrays.asList(expectedOids), + (object,expectedOid) -> expectedOid.equals(object.getOid()))) { + failAllow(message, type, (query==null?"null":query.toString())+", expected "+Arrays.toString(expectedOids)+", actual "+objects, null); + } + } + + @Override + public void assertCount(int count) throws Exception { + if (count != expectedOids.length) { + failAllow("count", type, query, expectedOids.length, count); + } + } + + }); + } + protected void assertSearch(Class type, ObjectQuery query, - Collection> options, int expectedResults) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + Collection> options, SearchAssertion assertion) throws Exception { Task task = taskManager.createTaskInstance(AbstractSecurityTest.class.getName() + ".assertSearchObjects"); OperationResult result = task.getResult(); try { logAttempt("search", type, query); List> objects = modelService.searchObjects(type, query, options, task, result); display("Search returned", objects.toString()); - if (objects.size() > expectedResults) { - failDeny("search", type, query, expectedResults, objects.size()); - } else if (objects.size() < expectedResults) { - failAllow("search", type, query, expectedResults, objects.size()); - } - result.computeStatus(); - TestUtil.assertSuccess(result); + assertion.assertObjects("search", objects); + assertSuccess(result); } catch (SecurityViolationException e) { // this should not happen result.computeStatus(); @@ -831,13 +905,8 @@ public boolean handle(PrismObject object, OperationResult parentResult) { }; modelService.searchObjectsIterative(type, query, handler, options, task, result); display("Search iterative returned", objects.toString()); - if (objects.size() > expectedResults) { - failDeny("searchIterative", type, query, expectedResults, objects.size()); - } else if (objects.size() < expectedResults) { - failAllow("searchIterative", type, query, expectedResults, objects.size()); - } - result.computeStatus(); - TestUtil.assertSuccess(result); + assertion.assertObjects("searchIterative", objects); + assertSuccess(result); } catch (SecurityViolationException e) { // this should not happen result.computeStatus(); @@ -851,13 +920,8 @@ public boolean handle(PrismObject object, OperationResult parentResult) { logAttempt("count", type, query); int numObjects = modelService.countObjects(type, query, options, task, result); display("Count returned", numObjects); - if (numObjects > expectedResults) { - failDeny("count", type, query, expectedResults, numObjects); - } else if (numObjects < expectedResults) { - failAllow("count", type, query, expectedResults, numObjects); - } - result.computeStatus(); - TestUtil.assertSuccess(result); + assertion.assertCount(numObjects); + assertSuccess(result); } catch (SecurityViolationException e) { // this should not happen result.computeStatus(); @@ -935,6 +999,24 @@ protected void assertAddAllow(File file, ModelExecuteOpti logAllow("add", object.getCompileTimeClass(), object.getOid(), null); } + protected void assertModifyMetadataDeny(Class type, String oid) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { + XMLGregorianCalendar oneHourAgo = XmlTypeConverter.addDuration(clock.currentTimeXMLGregorianCalendar(), "-PT1H"); + assertModifyDenyOptions(type, oid, getMetadataPath(MetadataType.F_MODIFY_TIMESTAMP), null, oneHourAgo); + assertModifyDenyOptions(type, oid, getMetadataPath(MetadataType.F_CREATE_CHANNEL), null, "hackHackHack"); + } + + protected void assertPasswordChangeDeny(Class type, String oid, String newPassword) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { + ProtectedStringType passwordPs = new ProtectedStringType(); + passwordPs.setClearValue(newPassword); + assertModifyDeny(type, oid, PASSWORD_PATH, passwordPs); + } + + protected void assertPasswordChangeAllow(Class type, String oid, String newPassword) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { + ProtectedStringType passwordPs = new ProtectedStringType(); + passwordPs.setClearValue(newPassword); + assertModifyAllow(type, oid, PASSWORD_PATH, passwordPs); + } + protected void assertModifyDeny(Class type, String oid, QName propertyName, Object... newRealValue) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { assertModifyDenyOptions(type, oid, propertyName, null, newRealValue); } @@ -1328,5 +1410,5 @@ protected void assertCanSearch(Stri protected ObjectQuery createMembersQuery(Class resultType, String roleOid) { return QueryBuilder.queryFor(resultType, prismContext).item(UserType.F_ROLE_MEMBERSHIP_REF).ref(roleOid).build(); } - + } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/SearchAssertion.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/SearchAssertion.java new file mode 100644 index 00000000000..079f0245e89 --- /dev/null +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/SearchAssertion.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2017 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.evolveum.midpoint.model.intest.security; + +import java.util.List; + +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; + +/** + * @author semancik + * + */ +public interface SearchAssertion { + + void assertObjects(String message, List> objects) throws Exception; + + void assertCount(int count) throws Exception; + +} diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityAdvanced.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityAdvanced.java index 37f22a2ba8e..b01cda6ef5c 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityAdvanced.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityAdvanced.java @@ -15,29 +15,30 @@ */ package com.evolveum.midpoint.model.intest.security; -import static com.evolveum.midpoint.test.IntegrationTestTools.display; import static org.testng.AssertJUnit.assertEquals; -import static org.testng.AssertJUnit.assertNull; import java.io.IOException; import java.util.Collection; +import javax.xml.datatype.XMLGregorianCalendar; + 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.model.api.RoleSelectionSpecification; import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.PrismReferenceValue; import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.prism.query.TypeFilter; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.util.PrismTestUtil; +import com.evolveum.midpoint.prism.xml.XmlTypeConverter; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.test.IntegrationTestTools; -import com.evolveum.midpoint.test.util.TestUtil; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; @@ -46,7 +47,9 @@ import com.evolveum.midpoint.util.exception.PolicyViolationException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentPolicyEnforcementType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType; @@ -72,14 +75,14 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti @Test public void test100AutzJackPersonaManagement() throws Exception { final String TEST_NAME = "test100AutzJackPersonaManagement"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_PERSONA_MANAGEMENT_OID); login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); assertGetAllow(UserType.class, USER_JACK_OID); assertGetDeny(UserType.class, USER_GUYBRUSH_OID); @@ -99,14 +102,14 @@ public void test100AutzJackPersonaManagement() throws Exception { @Test public void test102AutzLechuckPersonaManagement() throws Exception { final String TEST_NAME = "test102AutzLechuckPersonaManagement"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN - cleanupAutzTest(USER_LECHUCK_OID); + cleanupAutzTest(USER_LECHUCK_OID, 1); assignRole(USER_LECHUCK_OID, ROLE_PERSONA_MANAGEMENT_OID); login(USER_LECHUCK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); assertGetDeny(UserType.class, USER_JACK_OID); assertGetDeny(UserType.class, USER_GUYBRUSH_OID); @@ -127,14 +130,14 @@ public void test102AutzLechuckPersonaManagement() throws Exception { @Test public void test110AutzJackPersonaAdmin() throws Exception { final String TEST_NAME = "test110AutzJackAddPersonaAdmin"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_PERSONA_MANAGEMENT_OID); login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); assertAllow("assign application role 1 to jack", (task,result) -> assignRole(USER_JACK_OID, ROLE_PERSONA_ADMIN_OID, task, result)); @@ -182,7 +185,7 @@ public void test110AutzJackPersonaAdmin() throws Exception { @Test public void test120AutzJackDelagator() throws Exception { final String TEST_NAME = "test120AutzJackDelagator"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_DELEGATOR_OID); @@ -192,7 +195,7 @@ public void test120AutzJackDelagator() throws Exception { login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); assertReadAllow(NUMBER_OF_ALL_USERS); assertAddDeny(); @@ -234,6 +237,9 @@ public void test120AutzJackDelagator() throws Exception { display("Barbossa delegate", userBarbossa); assertAssignments(userBarbossa, 1); assertAssignedDeputy(userBarbossa, USER_JACK_OID); + + assertDeputySearchDelegatorRef(USER_JACK_OID, USER_BARBOSSA_OID); + assertDeputySearchAssignmentTarget(USER_JACK_OID, USER_BARBOSSA_OID); // Non-delegate. We should be able to read just the name. Not the assignments. PrismObject userRum = getUser(userRumRogersOid); @@ -242,7 +248,7 @@ public void test120AutzJackDelagator() throws Exception { login(USER_BARBOSSA_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); display("Logged in as Barbossa"); assertReadAllow(NUMBER_OF_ALL_USERS); @@ -252,7 +258,7 @@ public void test120AutzJackDelagator() throws Exception { login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); display("Logged in as Jack"); assertAllow("undelegate from Barbossa", @@ -270,7 +276,7 @@ public void test120AutzJackDelagator() throws Exception { login(USER_BARBOSSA_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); display("Logged in as Barbossa"); assertReadDeny(); @@ -290,11 +296,338 @@ public void test120AutzJackDelagator() throws Exception { assertGlobalStateUntouched(); } + + /** + * Assign a deputy, but this time with validFrom and validTo set to the future. + * The delegator role does NOT allow access to inactive delegations. + * MID-4172 + */ + @Test + public void test122AutzJackDelagatorValidity() throws Exception { + final String TEST_NAME = "test122AutzJackDelagatorValidity"; + displayTestTitle(TEST_NAME); + // GIVEN + cleanupAutzTest(USER_JACK_OID); + assignRole(USER_JACK_OID, ROLE_DELEGATOR_OID); - @Test + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + login(USER_JACK_USERNAME); + + // WHEN + displayWhen(TEST_NAME); + + PrismObject userJack = getUser(USER_JACK_OID); + assertAssignments(userJack, 1); + assertAssignedRole(userJack, ROLE_DELEGATOR_OID); + + PrismObject userBarbossa = getUser(USER_BARBOSSA_OID); + assertNoAssignments(userBarbossa); + + XMLGregorianCalendar startTs = clock.currentTimeXMLGregorianCalendar(); + + ActivationType activationType = new ActivationType(); + activationType.setValidFrom(XmlTypeConverter.addDuration(startTs, "PT2H")); + activationType.setValidTo(XmlTypeConverter.addDuration(startTs, "P1D")); + + // Good direction + assertAllow("delegate to Barbossa", + (task, result) -> { + assignDeputy(USER_BARBOSSA_OID, USER_JACK_OID, + assignment -> assignment.setActivation(activationType), task, result); + }); + + userJack = getUser(USER_JACK_OID); + display("Jack delegator", userJack); + assertAssignments(userJack, 1); + + userBarbossa = getUser(USER_BARBOSSA_OID); + display("Barbossa delegate", userBarbossa); + // Delegation is not active yet. Therefore jack cannot see it. + assertAssignments(userBarbossa, 0); + + assertDeputySearchDelegatorRef(USER_JACK_OID /* nothing */); + assertDeputySearchAssignmentTarget(USER_JACK_OID, USER_BARBOSSA_OID); // WRONG!!! +// assertDeputySearchAssignmentTarget(USER_JACK_OID /* nothing */); + + // Non-delegate. We should be able to read just the name. Not the assignments. + PrismObject userRum = getUser(userRumRogersOid); + display("User Rum Rogers", userRum); + assertNoAssignments(userRum); + + login(USER_BARBOSSA_USERNAME); + // WHEN + displayWhen(TEST_NAME); + display("Logged in as Barbossa"); + + // Delegation is not active yet. No access. + assertReadDeny(); + assertAddDeny(); + assertModifyDeny(); + assertDeleteDeny(); + + clockForward("PT3H"); + + login(USER_ADMINISTRATOR_USERNAME); + recomputeUser(USER_BARBOSSA_OID); + + // Delegation is active now + + login(USER_JACK_USERNAME); + // WHEN + + userBarbossa = getUser(USER_BARBOSSA_OID); + display("Barbossa delegate", userBarbossa); + assertAssignments(userBarbossa, 1); + assertAssignedDeputy(userBarbossa, USER_JACK_OID); + + assertDeputySearchDelegatorRef(USER_JACK_OID, USER_BARBOSSA_OID); + assertDeputySearchAssignmentTarget(USER_JACK_OID, USER_BARBOSSA_OID); + + login(USER_BARBOSSA_USERNAME); + // WHEN + displayWhen(TEST_NAME); + display("Logged in as Barbossa"); + + assertReadAllow(NUMBER_OF_ALL_USERS); + assertAddDeny(); + assertModifyDeny(); + assertDeleteDeny(); + + clockForward("P1D"); + + login(USER_ADMINISTRATOR_USERNAME); + recomputeUser(USER_BARBOSSA_OID); + + login(USER_BARBOSSA_USERNAME); + // WHEN + displayWhen(TEST_NAME); + display("Logged in as Barbossa"); + + // Delegation is not active any more. No access. + assertReadDeny(); + assertAddDeny(); + assertModifyDeny(); + assertDeleteDeny(); + + + login(USER_JACK_USERNAME); + // WHEN + displayWhen(TEST_NAME); + display("Logged in as Jack"); + + assertAllow("undelegate from Barbossa", + (task, result) -> { + unassignDeputy(USER_BARBOSSA_OID, USER_JACK_OID, + assignment -> assignment.setActivation(activationType), task, result); + }); + + userJack = getUser(USER_JACK_OID); + assertAssignments(userJack, 1); + + userBarbossa = getUser(USER_BARBOSSA_OID); + assertNoAssignments(userBarbossa); + + assertGlobalStateUntouched(); + + login(USER_BARBOSSA_USERNAME); + // WHEN + displayWhen(TEST_NAME); + display("Logged in as Barbossa"); + + assertReadDeny(); + assertAddDeny(); + assertModifyDeny(); + assertDeleteDeny(); + + assertDeny("delegate to Jack", + (task, result) -> { + assignDeputy(USER_JACK_OID, USER_BARBOSSA_OID, task, result); + }); + + assertDeny("delegate from Jack to Barbossa", + (task, result) -> { + assignDeputy(USER_BARBOSSA_OID, USER_JACK_OID, task, result); + }); + + assertGlobalStateUntouched(); + } + + /** + * Assign a deputy with validity. But this time there is a role that allows + * access to inactive delegations. + * MID-4172 + */ + @Test + public void test124AutzJackDelagatorPlusValidity() throws Exception { + final String TEST_NAME = "test124AutzJackDelagatorPlusValidity"; + displayTestTitle(TEST_NAME); + // GIVEN + cleanupAutzTest(USER_JACK_OID); + assignRole(USER_JACK_OID, ROLE_DELEGATOR_PLUS_OID); + + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + login(USER_JACK_USERNAME); + + // WHEN + displayWhen(TEST_NAME); + + PrismObject userJack = getUser(USER_JACK_OID); + assertAssignments(userJack, 1); + assertAssignedRole(userJack, ROLE_DELEGATOR_PLUS_OID); + + PrismObject userBarbossa = getUser(USER_BARBOSSA_OID); + assertNoAssignments(userBarbossa); + + XMLGregorianCalendar startTs = clock.currentTimeXMLGregorianCalendar(); + + ActivationType activationType = new ActivationType(); + activationType.setValidFrom(XmlTypeConverter.addDuration(startTs, "PT2H")); + activationType.setValidTo(XmlTypeConverter.addDuration(startTs, "P1D")); + + // Good direction + assertAllow("delegate to Barbossa", + (task, result) -> { + assignDeputy(USER_BARBOSSA_OID, USER_JACK_OID, + assignment -> assignment.setActivation(activationType), task, result); + }); + + userJack = getUser(USER_JACK_OID); + display("Jack delegator", userJack); + assertAssignments(userJack, 1); + + userBarbossa = getUser(USER_BARBOSSA_OID); + display("Barbossa delegate", userBarbossa); + assertAssignments(userBarbossa, 1); + assertAssignedDeputy(userBarbossa, USER_JACK_OID); + + // delegatorRef is allowed, but returns nothing. The delegation is not yet active, it is not in the delgatorRef. + assertDeputySearchDelegatorRef(USER_JACK_OID /* nothing */); + assertDeputySearchAssignmentTarget(USER_JACK_OID, USER_BARBOSSA_OID); + + // Non-delegate. We should be able to read just the name. Not the assignments. + PrismObject userRum = getUser(userRumRogersOid); + display("User Rum Rogers", userRum); + assertNoAssignments(userRum); + + login(USER_BARBOSSA_USERNAME); + // WHEN + displayWhen(TEST_NAME); + display("Logged in as Barbossa"); + + // Delegation is not active yet. No access. + assertReadDeny(); + assertAddDeny(); + assertModifyDeny(); + assertDeleteDeny(); + + clockForward("PT3H"); + + login(USER_ADMINISTRATOR_USERNAME); + recomputeUser(USER_BARBOSSA_OID); + + // Delegation is active now + + login(USER_JACK_USERNAME); + // WHEN + + userBarbossa = getUser(USER_BARBOSSA_OID); + display("Barbossa delegate", userBarbossa); + assertAssignments(userBarbossa, 1); + assertAssignedDeputy(userBarbossa, USER_JACK_OID); + + assertDeputySearchDelegatorRef(USER_JACK_OID, USER_BARBOSSA_OID); + assertDeputySearchAssignmentTarget(USER_JACK_OID, USER_BARBOSSA_OID); + + login(USER_BARBOSSA_USERNAME); + // WHEN + displayWhen(TEST_NAME); + display("Logged in as Barbossa"); + + assertReadAllow(NUMBER_OF_ALL_USERS); + assertAddDeny(); + assertModifyDeny(); + assertDeleteDeny(); + + clockForward("P1D"); + + login(USER_ADMINISTRATOR_USERNAME); + recomputeUser(USER_BARBOSSA_OID); + + // Delegation no longer active + + login(USER_JACK_USERNAME); + // WHEN + + userBarbossa = getUser(USER_BARBOSSA_OID); + display("Barbossa delegate", userBarbossa); + assertAssignments(userBarbossa, 1); + assertAssignedDeputy(userBarbossa, USER_JACK_OID); + + // delegatorRef is allowed, but returns nothing. The delegation is not yet active, it is not in the delgatorRef. + assertDeputySearchDelegatorRef(USER_JACK_OID /* nothing */); + assertDeputySearchAssignmentTarget(USER_JACK_OID, USER_BARBOSSA_OID); + + login(USER_BARBOSSA_USERNAME); + // WHEN + displayWhen(TEST_NAME); + display("Logged in as Barbossa"); + + // Delegation is not active any more. No access. + assertReadDeny(); + assertAddDeny(); + assertModifyDeny(); + assertDeleteDeny(); + + + login(USER_JACK_USERNAME); + // WHEN + displayWhen(TEST_NAME); + display("Logged in as Jack"); + + assertAllow("undelegate from Barbossa", + (task, result) -> { + unassignDeputy(USER_BARBOSSA_OID, USER_JACK_OID, + assignment -> assignment.setActivation(activationType), task, result); + }); + + userJack = getUser(USER_JACK_OID); + assertAssignments(userJack, 1); + + userBarbossa = getUser(USER_BARBOSSA_OID); + assertNoAssignments(userBarbossa); + + assertGlobalStateUntouched(); + + login(USER_BARBOSSA_USERNAME); + // WHEN + displayWhen(TEST_NAME); + display("Logged in as Barbossa"); + + assertReadDeny(); + assertAddDeny(); + assertModifyDeny(); + assertDeleteDeny(); + + assertDeny("delegate to Jack", + (task, result) -> { + assignDeputy(USER_JACK_OID, USER_BARBOSSA_OID, task, result); + }); + + assertDeny("delegate from Jack to Barbossa", + (task, result) -> { + assignDeputy(USER_BARBOSSA_OID, USER_JACK_OID, task, result); + }); + + assertGlobalStateUntouched(); + } + + + @Test public void test150AutzJackApproverUnassignRoles() throws Exception { final String TEST_NAME = "test150AutzJackApproverUnassignRoles"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_APPROVER_UNASSIGN_ROLES_OID); @@ -307,7 +640,7 @@ public void test150AutzJackApproverUnassignRoles() throws Exception { login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); assertGetAllow(RoleType.class, ROLE_ORDINARY_OID); assertGetDeny(RoleType.class, ROLE_PERSONA_ADMIN_OID); // no assignment @@ -339,7 +672,7 @@ public void test150AutzJackApproverUnassignRoles() throws Exception { @Test public void test151AutzJackApproverUnassignRolesAndRead() throws Exception { final String TEST_NAME = "test151AutzJackApproverUnassignRolesAndRead"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_APPROVER_UNASSIGN_ROLES_OID); @@ -349,7 +682,7 @@ public void test151AutzJackApproverUnassignRolesAndRead() throws Exception { login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); assertGetAllow(RoleType.class, ROLE_ORDINARY_OID); assertGetAllow(RoleType.class, ROLE_PERSONA_ADMIN_OID); // no assignment @@ -383,7 +716,7 @@ public void test151AutzJackApproverUnassignRolesAndRead() throws Exception { @Test public void test154AutzJackApproverRead() throws Exception { final String TEST_NAME = "test154AutzJackApproverRead"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_READ_BASIC_ITEMS_OID); @@ -392,7 +725,7 @@ public void test154AutzJackApproverRead() throws Exception { login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); PrismObject roleOrdinary = assertGetAllow(RoleType.class, ROLE_ORDINARY_OID); assertNoRoleMembershipRef(roleOrdinary); @@ -449,7 +782,7 @@ public void test154AutzJackApproverRead() throws Exception { @Test public void test155AutzJackApproverSelf() throws Exception { final String TEST_NAME = "test155AutzJackApproverSelf"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_SELF_OID); @@ -458,7 +791,7 @@ public void test155AutzJackApproverSelf() throws Exception { login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); assertGetDeny(RoleType.class, ROLE_ORDINARY_OID); assertGetDeny(RoleType.class, ROLE_PERSONA_ADMIN_OID); @@ -507,7 +840,7 @@ public void test155AutzJackApproverSelf() throws Exception { @Test public void test157AutzJackReadRoleMembers() throws Exception { final String TEST_NAME = "test157AutzJackReadRoleMembers"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_READ_ROLE_MEMBERS_OID); @@ -515,7 +848,7 @@ public void test157AutzJackReadRoleMembers() throws Exception { login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); PrismObject roleOrdinary = assertGetAllow(RoleType.class, ROLE_ORDINARY_OID); assertNoRoleMembershipRef(roleOrdinary); @@ -560,7 +893,7 @@ public void test157AutzJackReadRoleMembers() throws Exception { @Test public void test158AutzJackReadRoleMembersWrong() throws Exception { final String TEST_NAME = "test158AutzJackReadRoleMembersWrong"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_READ_ROLE_MEMBERS_WRONG_OID); @@ -568,7 +901,7 @@ public void test158AutzJackReadRoleMembersWrong() throws Exception { login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); PrismObject roleOrdinary = assertGetAllow(RoleType.class, ROLE_ORDINARY_OID); assertNoRoleMembershipRef(roleOrdinary); @@ -613,7 +946,7 @@ public void test158AutzJackReadRoleMembersWrong() throws Exception { @Test public void test159AutzJackReadRoleMembersNone() throws Exception { final String TEST_NAME = "test159AutzJackReadRoleMembersNone"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_READ_ROLE_MEMBERS_NONE_OID); @@ -621,7 +954,7 @@ public void test159AutzJackReadRoleMembersNone() throws Exception { login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); PrismObject roleOrdinary = assertGetAllow(RoleType.class, ROLE_ORDINARY_OID); assertNoRoleMembershipRef(roleOrdinary); @@ -716,7 +1049,7 @@ private void assert15xCommon() throws Exception { @Test public void test200AutzJackModifyOrgunit() throws Exception { final String TEST_NAME = "test200AutzJackModifyOrgunit"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_READ_SELF_MODIFY_ORGUNIT_OID); @@ -726,7 +1059,7 @@ public void test200AutzJackModifyOrgunit() throws Exception { login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); assertGetAllow(UserType.class, USER_JACK_OID); assertAddDeny(); @@ -777,7 +1110,7 @@ public void test200AutzJackModifyOrgunit() throws Exception { @Test public void test202AutzJackModifyOrgunitAndAssignRole() throws Exception { final String TEST_NAME = "test202AutzJackModifyOrgunitAndAssignRole"; - TestUtil.displayTestTitle(this, TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_READ_SELF_MODIFY_ORGUNIT_OID); @@ -788,7 +1121,7 @@ public void test202AutzJackModifyOrgunitAndAssignRole() throws Exception { login(USER_JACK_USERNAME); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); assertGetAllow(UserType.class, USER_JACK_OID); assertAddDeny(); @@ -845,8 +1178,8 @@ public void test202AutzJackModifyOrgunitAndAssignRole() throws Exception { } @Override - protected void cleanupAutzTest(String userOid) throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, ObjectAlreadyExistsException, PolicyViolationException, SecurityViolationException, IOException { - super.cleanupAutzTest(userOid); + protected void cleanupAutzTest(String userOid, int expectedAssignments) throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, ObjectAlreadyExistsException, PolicyViolationException, SecurityViolationException, IOException { + super.cleanupAutzTest(userOid, expectedAssignments); Task task = taskManager.createTaskInstance(TestSecurityAdvanced.class.getName() + ".cleanupAutzTest"); OperationResult result = task.getResult(); @@ -857,4 +1190,20 @@ protected void cleanupAutzTest(String userOid) throws ObjectNotFoundException, S assignRole(userCobbOid, ROLE_UNINTERESTING_OID, task, result); } + + private void assertDeputySearchDelegatorRef(String delegatorOid, String... expectedDeputyOids) throws Exception { + PrismReferenceValue rval = new PrismReferenceValue(delegatorOid, UserType.COMPLEX_TYPE); + rval.setRelation(SchemaConstants.ORG_DEPUTY); + ObjectQuery query = queryFor(UserType.class).item(UserType.F_DELEGATED_REF).ref(rval).build(); + assertSearch(UserType.class, query, expectedDeputyOids); + } + + private void assertDeputySearchAssignmentTarget(String delegatorOid, String... expectedDeputyOids) throws Exception { + PrismReferenceValue rval = new PrismReferenceValue(delegatorOid, UserType.COMPLEX_TYPE); + rval.setRelation(SchemaConstants.ORG_DEPUTY); + ObjectQuery query = queryFor(UserType.class) + .item(new ItemPath(UserType.F_ASSIGNMENT, AssignmentType.F_TARGET_REF)).ref(rval).build(); + assertSearch(UserType.class, query, expectedDeputyOids); + } + } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityBasic.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityBasic.java index 33fafb3cb90..8a9d520195b 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityBasic.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/security/TestSecurityBasic.java @@ -15,7 +15,6 @@ */ package com.evolveum.midpoint.model.intest.security; -import static com.evolveum.midpoint.test.IntegrationTestTools.display; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertNull; @@ -41,6 +40,7 @@ import com.evolveum.midpoint.prism.delta.ContainerDelta; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.delta.ReferenceDelta; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectQuery; @@ -1465,6 +1465,7 @@ public void test255AutzJackSelfAccountsReadWrite() throws Exception { // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_SELF_ACCOUNTS_READ_WRITE_OID); + assignAccount(USER_JACK_OID, RESOURCE_DUMMY_OID, null); assumeAssignmentPolicy(AssignmentPolicyEnforcementType.NONE); @@ -1528,6 +1529,7 @@ public void test256AutzJackSelfAccountsPartialControl() throws Exception { // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_SELF_ACCOUNTS_PARTIAL_CONTROL_OID); + assignAccount(USER_JACK_OID, RESOURCE_DUMMY_OID, null); assumeAssignmentPolicy(AssignmentPolicyEnforcementType.NONE); @@ -1568,10 +1570,8 @@ public void test256AutzJackSelfAccountsPartialControl() throws Exception { // Not even jack's account assertAddDeny(ACCOUNT_GUYBRUSH_DUMMY_FILE); - ProtectedStringType passwordPs = new ProtectedStringType(); - passwordPs.setClearValue("nbusr123"); - assertModifyDeny(UserType.class, USER_JACK_OID, PASSWORD_PATH, passwordPs); - assertModifyDeny(UserType.class, USER_GUYBRUSH_OID, PASSWORD_PATH, passwordPs); + assertPasswordChangeDeny(UserType.class, USER_JACK_OID, "nbusr123"); + assertPasswordChangeDeny(UserType.class, USER_GUYBRUSH_OID, "nbusr123"); Task task = taskManager.createTaskInstance(TEST_NAME); OperationResult result = task.getResult(); @@ -1611,6 +1611,7 @@ public void test258AutzJackSelfAccountsPartialControlPassword() throws Exception // GIVEN cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_SELF_ACCOUNTS_PARTIAL_CONTROL_PASSWORD_OID); + assignAccount(USER_JACK_OID, RESOURCE_DUMMY_OID, null); assumeAssignmentPolicy(AssignmentPolicyEnforcementType.NONE); @@ -1651,11 +1652,9 @@ public void test258AutzJackSelfAccountsPartialControlPassword() throws Exception // Not even jack's account assertAddDeny(ACCOUNT_GUYBRUSH_DUMMY_FILE); - ProtectedStringType passwordPs = new ProtectedStringType(); - passwordPs.setClearValue("nbusr123"); - assertModifyAllow(UserType.class, USER_JACK_OID, PASSWORD_PATH, passwordPs); - assertModifyDeny(UserType.class, USER_GUYBRUSH_OID, PASSWORD_PATH, passwordPs); - + assertPasswordChangeAllow(UserType.class, USER_JACK_OID, "nbusr123"); + assertPasswordChangeDeny(UserType.class, USER_GUYBRUSH_OID, "nbusr123"); + Task task = taskManager.createTaskInstance(TEST_NAME); OperationResult result = task.getResult(); PrismObjectDefinition rDef = modelInteractionService.getEditObjectDefinition(user, AuthorizationPhaseType.REQUEST, task, result); @@ -1672,6 +1671,8 @@ public void test260AutzJackObjectFilterLocationShadowRole() throws Exception { cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_FILTER_OBJECT_USER_LOCATION_SHADOWS_OID); login(USER_JACK_USERNAME); + + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.NONE); // WHEN displayWhen(TEST_NAME); @@ -1711,6 +1712,20 @@ public void test260AutzJackObjectFilterLocationShadowRole() throws Exception { assertGetAllow(ShadowType.class, accountRedOid); assertGlobalStateUntouched(); + + displayCleanup(TEST_NAME); + login(USER_ADMINISTRATOR_USERNAME); + + Task task = createTask(TEST_NAME); + PrismObject account = PrismTestUtil.parseObject(ACCOUNT_JACK_DUMMY_RED_FILE); + account.setOid(accountRedOid); + ObjectDelta userDelta = ObjectDelta.createEmptyModifyDelta(UserType.class, USER_JACK_OID, prismContext); + ReferenceDelta accountDelta = ReferenceDelta.createModificationDelete(UserType.F_LINK_REF, getUserDefinition(), account); + userDelta.addModification(accountDelta); + executeChanges(userDelta, null, task, task.getResult()); + + user = getUser(USER_JACK_OID); + assertLinks(user, 0); } @@ -1771,7 +1786,7 @@ public void test270AutzJackAssignApplicationRoles() throws Exception { assertDeleteDeny(); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertAssignedRole(user, ROLE_ASSIGN_APPLICATION_ROLES_OID); assertAllow("assign application role to jack", @@ -1779,7 +1794,7 @@ public void test270AutzJackAssignApplicationRoles() throws Exception { ); user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAssignedRole(user, ROLE_APPLICATION_1_OID); assertDeny("assign business role to jack", @@ -1790,7 +1805,7 @@ public void test270AutzJackAssignApplicationRoles() throws Exception { ); user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); RoleSelectionSpecification spec = getAssignableRoleSpecification(getUser(USER_JACK_OID)); assertRoleTypes(spec, "application", "nonexistent"); @@ -1823,7 +1838,7 @@ public void test272AutzJackAssignAnyRoles() throws Exception { assertDeleteDeny(); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertAssignedRole(user, ROLE_ASSIGN_ANY_ROLES_OID); assertAllow("assign application role to jack", @@ -1831,7 +1846,7 @@ public void test272AutzJackAssignAnyRoles() throws Exception { ); user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAssignedRole(user, ROLE_APPLICATION_1_OID); assertAllow("assign business role to jack", @@ -1842,7 +1857,7 @@ public void test272AutzJackAssignAnyRoles() throws Exception { ); user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); RoleSelectionSpecification spec = getAssignableRoleSpecification(getUser(USER_JACK_OID)); assertRoleTypes(spec); @@ -1878,7 +1893,7 @@ public void test273AutzJackRedyAssignmentExceptionRules() throws Exception { assertDeleteDeny(); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertAssignedRole(user, ROLE_ASSIGN_ANY_ROLES_OID); assertDeny("assign application role to jack", @@ -1892,7 +1907,7 @@ public void test273AutzJackRedyAssignmentExceptionRules() throws Exception { ); user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertDeny("assign application role to jack", (task, result) -> assignRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, null, @@ -1906,7 +1921,7 @@ public void test273AutzJackRedyAssignmentExceptionRules() throws Exception { user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertGlobalStateUntouched(); } @@ -1932,14 +1947,14 @@ public void test274AutzJackAssignNonApplicationRoles() throws Exception { assertDeleteDeny(); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertAssignedRole(user, ROLE_ASSIGN_NON_APPLICATION_ROLES_OID); assertAllow("assign business role to jack", (task, result) -> assignRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAssignedRole(user, ROLE_BUSINESS_1_OID); assertDeny("assign application role to jack", @@ -1949,7 +1964,7 @@ public void test274AutzJackAssignNonApplicationRoles() throws Exception { (task, result) -> unassignRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); RoleSelectionSpecification spec = getAssignableRoleSpecification(getUser(USER_JACK_OID)); assertRoleTypes(spec); @@ -1979,14 +1994,14 @@ public void test275aAutzJackAssignRequestableRoles() throws Exception { assertDeleteDeny(); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertAssignedRole(user, ROLE_ASSIGN_REQUESTABLE_ROLES_OID); assertAllow("assign business role to jack", (task, result) -> assignRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAssignedRole(user, ROLE_BUSINESS_1_OID); assertDeny("assign application role to jack", @@ -1996,7 +2011,7 @@ public void test275aAutzJackAssignRequestableRoles() throws Exception { (task, result) -> unassignRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); RoleSelectionSpecification spec = getAssignableRoleSpecification(getUser(USER_JACK_OID)); assertRoleTypes(spec); @@ -2023,7 +2038,7 @@ public void test275bAutzJackAssignRequestableOrgs() throws Exception { // WHEN displayWhen(TEST_NAME); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertAssignedRole(user, ROLE_END_USER_REQUESTABLE_ABSTACTROLES_OID); assertAllow("assign requestable org to jack", @@ -2073,14 +2088,14 @@ public void test276AutzJackAssignRequestableRolesWithOrgRef() throws Exception { assertDeleteDeny(); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertAssignedRole(user, ROLE_ASSIGN_REQUESTABLE_ROLES_OID); assertAllow("assign business role to jack", (task, result) -> assignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, ORG_MINISTRY_OF_RUM_OID, null, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAssignedRole(user, ROLE_BUSINESS_1_OID); assertDeny("assign application role to jack", @@ -2090,8 +2105,8 @@ public void test276AutzJackAssignRequestableRolesWithOrgRef() throws Exception { (task, result) -> unassignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, ORG_MINISTRY_OF_RUM_OID, null, task, result)); user = getUser(USER_JACK_OID); - display("user after (expected 2 assignments)", user); - assertAssignments(user, 2); + display("user after (expected 1 assignments)", user); + assertAssignments(user, 1); RoleSelectionSpecification spec = getAssignableRoleSpecification(getUser(USER_JACK_OID)); assertRoleTypes(spec); @@ -2126,38 +2141,38 @@ public void test277AutzJackAssignRequestableRolesWithOrgRefSecondTime() throws E assertDeleteDeny(); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertAssignedRole(user, ROLE_ASSIGN_REQUESTABLE_ROLES_OID); assertAllow("assign business role to jack (no param)", (task, result) -> assignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, null, null, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAssignedRole(user, ROLE_BUSINESS_1_OID); assertAllow("assign business role to jack (org MoR)", (task, result) -> assignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, ORG_MINISTRY_OF_RUM_OID, null, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 4); - display("user after (expected 4 assignments)", user); + assertAssignments(user, 3); + display("user after (expected 3 assignments)", user); assertAssignedRole(user, ROLE_BUSINESS_1_OID); assertAllow("assign business role to jack (org Scumm)", (task, result) -> assignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, ORG_SCUMM_BAR_OID, null, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 5); - display("user after (expected 5 assignments)", user); + assertAssignments(user, 4); + display("user after (expected 4 assignments)", user); assertAssignedRole(user, ROLE_BUSINESS_1_OID); assertAllow("unassign business role from jack (org Scumm)", (task, result) -> unassignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, ORG_SCUMM_BAR_OID, null, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 4); - display("user after (expected 4 assignments)", user); + assertAssignments(user, 3); + display("user after (expected 3 assignments)", user); assertAssignedRole(user, ROLE_BUSINESS_1_OID); assertDeny("assign application role to jack", @@ -2167,15 +2182,15 @@ public void test277AutzJackAssignRequestableRolesWithOrgRefSecondTime() throws E (task, result) -> unassignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, null, null, task, result)); user = getUser(USER_JACK_OID); - display("user after (expected 3 assignments)", user); - assertAssignments(user, 3); + display("user after (expected 2 assignments)", user); + assertAssignments(user, 2); assertAllow("unassign business role from jack (org MoR)", (task, result) -> unassignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, ORG_MINISTRY_OF_RUM_OID, null, task, result)); user = getUser(USER_JACK_OID); - display("user after (expected 2 assignments)", user); - assertAssignments(user, 2); + display("user after (expected 1 assignments)", user); + assertAssignments(user, 1); RoleSelectionSpecification spec = getAssignableRoleSpecification(getUser(USER_JACK_OID)); assertRoleTypes(spec); @@ -2208,14 +2223,14 @@ public void test278AutzJackAssignRequestableRolesWithOrgRefTweakedDelta() throws assertDeleteDeny(); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertAssignedRole(user, ROLE_ASSIGN_REQUESTABLE_ROLES_OID); assertAllow("assign business role to jack", (task, result) -> assignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, ORG_MINISTRY_OF_RUM_OID, null, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAssignedRole(user, ROLE_BUSINESS_1_OID); assertDeny("assign application role to jack", @@ -2242,7 +2257,7 @@ public void test278AutzJackAssignRequestableRolesWithOrgRefTweakedDelta() throws user = getUser(USER_JACK_OID); display("user after (expected 2 assignments)", user); - assertAssignments(user, 2); + assertAssignments(user, 1); RoleSelectionSpecification spec = getAssignableRoleSpecification(getUser(USER_JACK_OID)); assertRoleTypes(spec); @@ -2275,7 +2290,7 @@ public void test279AutzJackAssignRequestableRolesWithTenantRef() throws Exceptio assertDeleteDeny(); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertAssignedRole(user, ROLE_ASSIGN_REQUESTABLE_ROLES_OID); assertAllow("assign business role to jack", @@ -2283,7 +2298,7 @@ public void test279AutzJackAssignRequestableRolesWithTenantRef() throws Exceptio assignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, null, ORG_GOVERNOR_OFFICE_OID, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAssignedRole(user, ROLE_BUSINESS_1_OID); assertDeny("assign application role to jack", new Attempt() { @@ -2298,8 +2313,8 @@ public void run(Task task, OperationResult result) throws Exception { unassignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, null, ORG_GOVERNOR_OFFICE_OID, task, result)); user = getUser(USER_JACK_OID); - display("user after (expected 2 assignments)", user); - assertAssignments(user, 2); + display("user after (expected 1 assignments)", user); + assertAssignments(user, 1); RoleSelectionSpecification spec = getAssignableRoleSpecification(getUser(USER_JACK_OID)); assertRoleTypes(spec); @@ -2317,6 +2332,10 @@ public void test280AutzJackEndUser() throws Exception { cleanupAutzTest(USER_JACK_OID); assignRole(USER_JACK_OID, ROLE_END_USER_OID); + + PrismObject user = getUser(USER_JACK_OID); + assertAssignments(user, 1); + assertLinks(user, 0); assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); @@ -2324,42 +2343,66 @@ public void test280AutzJackEndUser() throws Exception { // WHEN displayWhen(TEST_NAME); - - assertGetAllow(UserType.class, USER_JACK_OID); + assertGetDeny(UserType.class, USER_JACK_OID, SelectorOptions.createCollection(GetOperationOptions.createRaw())); assertGetDeny(UserType.class, USER_GUYBRUSH_OID); assertGetDeny(UserType.class, USER_GUYBRUSH_OID, SelectorOptions.createCollection(GetOperationOptions.createRaw())); - + assertSearch(UserType.class, null, 1); assertSearch(UserType.class, createNameQuery(USER_JACK_USERNAME), 1); assertSearchDeny(UserType.class, createNameQuery(USER_JACK_USERNAME), SelectorOptions.createCollection(GetOperationOptions.createRaw())); assertSearch(UserType.class, createNameQuery(USER_GUYBRUSH_USERNAME), 0); assertSearchDeny(UserType.class, createNameQuery(USER_GUYBRUSH_USERNAME), SelectorOptions.createCollection(GetOperationOptions.createRaw())); - + assertAddDeny(); assertModifyDeny(); assertDeleteDeny(); + + assertModifyMetadataDeny(UserType.class, USER_JACK_OID); + assertModifyMetadataDeny(UserType.class, USER_GUYBRUSH_OID); - PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); - - user = getUser(USER_JACK_OID); - + assertPasswordChangeAllow(UserType.class, USER_JACK_OID, "nbusr123"); + assertPasswordChangeDeny(UserType.class, USER_GUYBRUSH_OID, "nbusr123"); + // MID-3136 assertAllow("assign business role to jack", (task, result) -> assignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, null, ORG_GOVERNOR_OFFICE_OID, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAssignedRole(user, ROLE_BUSINESS_1_OID); assertDeny("assign application role to jack", (task, result) -> assignRole(USER_JACK_OID, ROLE_BUSINESS_2_OID, task, result)); - + // End-user role has authorization to assign, but not to unassign assertDeny("unassign business role from jack", (task, result) -> unassignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, null, ORG_GOVERNOR_OFFICE_OID, task, result)); + user = getUser(USER_JACK_OID); + display("user after (expected 3 assignments)", user); + assertAssignments(user, 2); + + assertAllow("assign basic role to jack", + (task, result) -> assignRole(USER_JACK_OID, ROLE_BASIC_OID, task, result)); + + user = getUser(USER_JACK_OID); + display("user after (expected 3 assignments)", user); + assertAssignments(user, 3); + + String accountOid = getSingleLinkOid(user); + + PrismObject accountShadow = assertGetAllow(ShadowType.class, accountOid); + display("account shadow", accountShadow); + + assertPasswordChangeAllow(UserType.class, USER_JACK_OID, "nbusr321"); + assertPasswordChangeDeny(UserType.class, USER_GUYBRUSH_OID, "nbusr321"); + + assertPasswordChangeAllow(ShadowType.class, accountOid, "nbusr231"); + + assertDeny("unassign basic role from jack", + (task, result) -> unassignRole(USER_JACK_OID, ROLE_BASIC_OID, task, result)); + user = getUser(USER_JACK_OID); display("user after (expected 3 assignments)", user); assertAssignments(user, 3); @@ -2386,7 +2429,7 @@ public void test281AutzJackEndUserSecondTime() throws Exception { displayWhen(TEST_NAME); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); user = getUser(USER_JACK_OID); @@ -2395,7 +2438,7 @@ public void test281AutzJackEndUserSecondTime() throws Exception { (task, result) -> assignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, null, null, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAssignedRole(user, ROLE_BUSINESS_1_OID); // MID-3136 @@ -2403,7 +2446,7 @@ public void test281AutzJackEndUserSecondTime() throws Exception { (task, result) -> assignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, null, ORG_GOVERNOR_OFFICE_OID, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 4); + assertAssignments(user, 3); assertAssignedRole(user, ROLE_BUSINESS_1_OID); assertDeny("assign application role to jack", new Attempt() { @@ -2418,8 +2461,8 @@ public void run(Task task, OperationResult result) throws Exception { (task, result) -> unassignParametricRole(USER_JACK_OID, ROLE_BUSINESS_1_OID, null, ORG_GOVERNOR_OFFICE_OID, task, result)); user = getUser(USER_JACK_OID); - display("user after (expected 4 assignments)", user); - assertAssignments(user, 4); + display("user after (expected 3 assignments)", user); + assertAssignments(user, 3); assertGlobalStateUntouched(); @@ -2459,7 +2502,7 @@ public void test282AutzJackEndUserAndModify() throws Exception { assertDeleteDeny(); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAllow("modify jack's familyName", (task, result) -> modifyObjectReplaceProperty(UserType.class, USER_JACK_OID, new ItemPath(UserType.F_FAMILY_NAME), task, result, PrismTestUtil.createPolyString("changed"))); @@ -2495,7 +2538,7 @@ public void test283AutzJackModifyAndEndUser() throws Exception { assertDeleteDeny(); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAllow("modify jack's familyName", (task, result) -> modifyObjectReplaceProperty(UserType.class, USER_JACK_OID, new ItemPath(UserType.F_FAMILY_NAME), task, result, PrismTestUtil.createPolyString("changed"))); @@ -2527,14 +2570,14 @@ public void test290AutzJackRoleOwnerAssign() throws Exception { assertDeleteDeny(); PrismObject user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); assertAssignedRole(user, ROLE_ROLE_OWNER_ASSIGN_OID); assertAllow("assign application role 1 to jack", (task,result) -> assignRole(USER_JACK_OID, ROLE_APPLICATION_1_OID, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 3); + assertAssignments(user, 2); assertAssignedRole(user, ROLE_APPLICATION_1_OID); assertDeny("assign application role 2 to jack", new Attempt() { @@ -2548,7 +2591,7 @@ public void run(Task task, OperationResult result) throws Exception { (task,result) -> unassignRole(USER_JACK_OID, ROLE_APPLICATION_1_OID, task, result)); user = getUser(USER_JACK_OID); - assertAssignments(user, 2); + assertAssignments(user, 1); RoleSelectionSpecification spec = getAssignableRoleSpecification(getUser(USER_JACK_OID)); assertRoleTypes(spec); diff --git a/model/model-intest/src/test/resources/security/role-basic.xml b/model/model-intest/src/test/resources/security/role-basic.xml index 3bb0ae3562f..8c713dc3ef9 100644 --- a/model/model-intest/src/test/resources/security/role-basic.xml +++ b/model/model-intest/src/test/resources/security/role-basic.xml @@ -1,5 +1,5 @@ + + Universal Self Delegator Pl + Like delegator, but can also access inactive delegations + true + + authz-read-basic + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + name + + + authz-read-self + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + self + + + + authz-read-delagate-assignments + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#read + + UserType + + self + true + + + assignment + roleMembershipRef + delegatedRef + + + delegator-req + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#delegate + request + + UserType + + + self + + + + delegator-exec-user + + Quite strong universal execution rights are needed here. We are going to modify other users + (deputy assignments are in the delegate user, not delegator). + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#modify + execution + + UserType + + + + delegator-exec-shadow + + Quite strong universal execution rights are needed here. We are going to modify other users + (deputy assignments are in the delegate user, not delegator). Modification of other users + may mean also creation/modification/deletion of their accounts. + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#add + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#modify + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#delete + execution + + ShadowType + + + diff --git a/model/model-intest/src/test/resources/security/role-end-user.xml b/model/model-intest/src/test/resources/security/role-end-user.xml index 28cd1641d29..84f0d0da710 100644 --- a/model/model-intest/src/test/resources/security/role-end-user.xml +++ b/model/model-intest/src/test/resources/security/role-end-user.xml @@ -125,17 +125,17 @@ credentials assignment - parentOrgRef - roleMembershipRef - self-shadow-execution-modify + self-shadow-execution-add-modify-delete - Authorization that allows to self-modification of some properties on user's accounts, but only in execution phase. - The limitation real limitation of these operations is done in the request phase. + Authorization that allows to self-modification of user's accounts, but only in execution phase. + The real limitation of these operations is done in the request phase. + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#add http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#modify + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#delete execution ShadowType @@ -143,7 +143,6 @@ self - credentials 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 2e3ee15bd64..175025d3bf9 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 @@ -814,6 +814,13 @@ protected void renameObject(Class type, String oid, St modifyObjectReplaceProperty(type, oid, ObjectType.F_NAME, task, result, createPolyString(newName)); } + protected void recomputeUser(String userOid) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { + Task task = createTask("recomputeUser"); + OperationResult result = task.getResult(); + modelService.recompute(UserType.class, userOid, null, task, result); + assertSuccess(result); + } + protected void recomputeUser(String userOid, Task task, OperationResult result) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { modelService.recompute(UserType.class, userOid, null, task, result); } @@ -1446,8 +1453,7 @@ protected Collection Collection> executeChangesAssertSuccess(ObjectDelta objectDelta, ModelExecuteOptions options, Task task, OperationResult result) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { Collection> rv = executeChanges(objectDelta, options, task, result); - result.computeStatus(); - TestUtil.assertSuccess(result); + assertSuccess(result); return rv; } @@ -1455,8 +1461,7 @@ protected void assignAccount(String userOid, String resourceOid, String intent) Task task = taskManager.createTaskInstance(AbstractModelIntegrationTest.class+".assignAccount"); OperationResult result = task.getResult(); assignAccount(userOid, resourceOid, intent, task, result); - result.computeStatus(); - TestUtil.assertSuccess(result); + assertSuccess(result); } protected void assignAccount(String userOid, String resourceOid, String intent, Task task, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { @@ -1465,6 +1470,13 @@ protected void assignAccount(String userOid, String resourceOid, String intent, modelService.executeChanges(deltas, null, task, result); } + protected void unassignAccount(String userOid, String resourceOid, String intent) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { + Task task = taskManager.createTaskInstance(AbstractModelIntegrationTest.class+".assignAccount"); + OperationResult result = task.getResult(); + unassignAccount(userOid, resourceOid, intent, task, result); + assertSuccess(result); + } + protected void unassignAccount(String userOid, String resourceOid, String intent, Task task, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { ObjectDelta userDelta = createAccountAssignmentUserDelta(userOid, resourceOid, intent, false); Collection> deltas = MiscSchemaUtil.createCollection(userDelta); @@ -1819,7 +1831,7 @@ protected void modifyDeputyAssignmentLimits(String userDeputyOid, String userTar protected void assertAssignedDeputy(PrismObject focus, String targetUserOid) { MidPointAsserts.assertAssigned(focus, targetUserOid, UserType.COMPLEX_TYPE, SchemaConstants.ORG_DEPUTY); } - + protected static void assertAssignedOrgs(PrismObject user, String... orgOids) { MidPointAsserts.assertAssignedOrgs(user, orgOids); } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectReferenceResolver.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectReferenceResolver.java index 5b2f25819ec..27c8ec68408 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectReferenceResolver.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectReferenceResolver.java @@ -40,6 +40,9 @@ import com.evolveum.midpoint.provisioning.ucf.api.ConnectorInstance; import com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException; import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.repo.common.expression.ExpressionFactory; +import com.evolveum.midpoint.repo.common.expression.ExpressionUtil; +import com.evolveum.midpoint.repo.common.expression.ExpressionVariables; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.ResultHandler; import com.evolveum.midpoint.schema.SelectorOptions; @@ -75,8 +78,9 @@ public class ResourceObjectReferenceResolver { private static final Trace LOGGER = TraceManager.getTrace(ResourceObjectReferenceResolver.class); - @Autowired(required = true) - private PrismContext prismContext; + @Autowired private PrismContext prismContext; + @Autowired private ExpressionFactory expressionFactory; + @Autowired private ShadowManager shadowManager; @Autowired(required = true) @Qualifier("cacheRepositoryService") @@ -86,9 +90,6 @@ public class ResourceObjectReferenceResolver { @Qualifier("shadowCacheProvisioner") private ShadowCache shadowCache; - @Autowired(required = true) - private ShadowManager shadowManager; - PrismObject resolve(ProvisioningContext ctx, ResourceObjectReferenceType resourceObjectReference, QName objectClass, final String desc, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, @@ -118,8 +119,11 @@ PrismObject resolve(ProvisioningContext ctx, ResourceObjectReference subctx.assertDefinition(); ObjectQuery refQuery = QueryJaxbConvertor.createObjectQuery(ShadowType.class, resourceObjectReference.getFilter(), prismContext); + // No variables. At least not now. We expect that mostly constants will be used here. + ExpressionVariables variables = new ExpressionVariables(); + ObjectQuery evaluatedRefQuery = ExpressionUtil.evaluateQueryExpressions(refQuery, variables, expressionFactory, prismContext, desc, ctx.getTask(), result); ObjectFilter baseFilter = ObjectQueryUtil.createResourceAndObjectClassFilter(ctx.getResource().getOid(), objectClass, prismContext); - ObjectFilter filter = AndFilter.createAnd(baseFilter, refQuery.getFilter()); + ObjectFilter filter = AndFilter.createAnd(baseFilter, evaluatedRefQuery.getFilter()); ObjectQuery query = ObjectQuery.createObjectQuery(filter); // TODO: implement "repo" search strategies diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java index a905b2fa6b7..b524ac8eebd 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java @@ -2143,4 +2143,8 @@ protected void waitForThreads(ParallelTestThread[] threads, long timeout) throws } } } + + protected ItemPath getMetadataPath(QName propName) { + return new ItemPath(ObjectType.F_METADATA, propName); + } } diff --git a/repo/repo-test-util/src/main/resources/test-config.xml b/repo/repo-test-util/src/main/resources/test-config.xml index 9d7a6f6e518..9f36869304a 100644 --- a/repo/repo-test-util/src/main/resources/test-config.xml +++ b/repo/repo-test-util/src/main/resources/test-config.xml @@ -72,6 +72,8 @@ Bla bla bla dc=example,dc=com secret + DC=ad,DC=evolveum,DC=com + CN=Users,DC=ad,DC=evolveum,DC=com \ No newline at end of file diff --git a/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/AuthorizationConstants.java b/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/AuthorizationConstants.java index 331effa5676..f58194f091a 100644 --- a/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/AuthorizationConstants.java +++ b/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/AuthorizationConstants.java @@ -15,10 +15,18 @@ */ package com.evolveum.midpoint.security.api; +import java.util.Arrays; +import java.util.Collection; + import javax.xml.namespace.QName; +import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.util.QNameUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; /** * @author semancik @@ -408,5 +416,49 @@ public class AuthorizationConstants { //ui authorization for CSV export button (will be applied everywhere over mp) public static final QName AUTZ_UI_ADMIN_CSV_EXPORT_ACTION_QNAME = new QName(NS_AUTHORIZATION_UI, "adminCSVexport"); public static final String AUTZ_UI_ADMIN_CSV_EXPORT_ACTION_URI = QNameUtil.qNameToUri(AUTZ_UI_ADMIN_CSV_EXPORT_ACTION_QNAME); + + /** + * Those are the items that midPoint logic controls directly. They have exception from execution-phase + * authorization enforcement. Their modification in execution phase is always allowed. If it was not + * allowed then midPoint won't be able to function properly and it may even lead to security issues. + * + * Note: this applies only to execution phase. Those items are still controlled by regular authorizations + * for request phase. Therefore these exceptions do NOT allow user to modify those items. Attempt to do so + * must pass through request-phase authorization first. This exception only allows midPoint logic to modify + * those properties without explicit authorizations. + * + * Motivation: Strictly speaking, there would be no need for these exceptions. The modification can be + * allowed by regular authorizations. However, that would mean, that every practical authorization must + * contain those items. That is error-prone, it is a maintenance burden and it is even an obstacle for + * evolvability. E.g. if similar properties are added in future midPoint versions (which is likely) then + * all existing authorizations much be updated. The cost of slightly increased perceived security is not + * justified by those operational issues. + */ + public static final Collection EXECUTION_ITEMS_ALLOWED_BY_DEFAULT = Arrays.asList( + new ItemPath(ObjectType.F_METADATA), + new ItemPath(ObjectType.F_PARENT_ORG_REF), + new ItemPath(ObjectType.F_TENANT_REF), + new ItemPath(ObjectType.F_TRIGGER), + new ItemPath(FocusType.F_ACTIVATION, ActivationType.F_ARCHIVE_TIMESTAMP), + new ItemPath(FocusType.F_ACTIVATION, ActivationType.F_DISABLE_REASON), + new ItemPath(FocusType.F_ACTIVATION, ActivationType.F_DISABLE_TIMESTAMP), + new ItemPath(FocusType.F_ACTIVATION, ActivationType.F_EFFECTIVE_STATUS), + new ItemPath(FocusType.F_ACTIVATION, ActivationType.F_ENABLE_TIMESTAMP), + new ItemPath(FocusType.F_ACTIVATION, ActivationType.F_LOCKOUT_EXPIRATION_TIMESTAMP), + new ItemPath(FocusType.F_ACTIVATION, ActivationType.F_LOCKOUT_STATUS), + new ItemPath(FocusType.F_ACTIVATION, ActivationType.F_VALIDITY_CHANGE_TIMESTAMP), + new ItemPath(FocusType.F_ACTIVATION, ActivationType.F_VALIDITY_STATUS), + new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_METADATA), + new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_POLICY_SITUATION), + new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_TRIGGERED_POLICY_RULE), + new ItemPath(FocusType.F_DELEGATED_REF), + new ItemPath(FocusType.F_ITERATION), + new ItemPath(FocusType.F_ITERATION_TOKEN), +// new ItemPath(FocusType.F_LINK_REF), // in fact, linkRef may be omitted here. link/unlink is done after execution authorizations are applied + new ItemPath(FocusType.F_PERSONA_REF), + new ItemPath(FocusType.F_ROLE_INFLUENCE_REF), + new ItemPath(FocusType.F_ROLE_MEMBERSHIP_REF), + new ItemPath(FocusType.F_TRIGGERED_POLICY_RULE) + ); } diff --git a/repo/security-impl/src/main/java/com/evolveum/midpoint/security/impl/SecurityEnforcerImpl.java b/repo/security-impl/src/main/java/com/evolveum/midpoint/security/impl/SecurityEnforcerImpl.java index 09e19a7cd63..00b79f3c967 100644 --- a/repo/security-impl/src/main/java/com/evolveum/midpoint/security/impl/SecurityEnforcerImpl.java +++ b/repo/security-impl/src/main/java/com/evolveum/midpoint/security/impl/SecurityEnforcerImpl.java @@ -16,7 +16,6 @@ package com.evolveum.midpoint.security.impl; import com.evolveum.midpoint.prism.*; -import com.evolveum.midpoint.prism.Visitor; import com.evolveum.midpoint.prism.delta.ContainerDelta; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; @@ -33,6 +32,7 @@ import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.security.api.*; import com.evolveum.midpoint.util.Producer; +import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.AuthorizationException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; @@ -209,7 +209,7 @@ private boolean isAuthorizedInterna if (decision == null || decision == AuthorizationDecisionType.ALLOW) { // if there is more than one role which specify // different authz (e.g one role specify allow for whole - // objet, the other role specify allow only for some + // object, the other role specify allow only for some // attributes. this ended with allow for whole object (MID-2018) Collection allowed = getItems(autz); if (allow && allowedItems.isEmpty()){ @@ -251,9 +251,9 @@ private boolean isAuthorizedInterna // all items in the object and delta must be allowed if (delta != null) { - allow = processAuthorizationDelta(delta, allowedItems); + allow = processAuthorizationDelta(delta, allowedItems, phase); } else if (object != null) { - allow = processAuthorizationObject(object, allowedItems); + allow = processAuthorizationObject(object, allowedItems, phase); } } } @@ -264,21 +264,21 @@ private boolean isAuthorizedInterna return allow; } - private boolean processAuthorizationObject(PrismContainer object, final Collection allowedItems) { - return isContainerAllowed(object.getValue(), allowedItems); + private boolean processAuthorizationObject(PrismContainer object, final Collection allowedItems, AuthorizationPhaseType phase) { + return isContainerAllowed(object.getValue(), allowedItems, phase); } - private boolean processAuthorizationContainerDelta(ContainerDelta cdelta, final Collection allowedItems) { + private boolean processAuthorizationContainerDelta(ContainerDelta cdelta, final Collection allowedItems, AuthorizationPhaseType phase) { final MutableBoolean itemDecision = new MutableBoolean(true); cdelta.foreach(cval -> { - if (!isContainerAllowed(cval, allowedItems)) { + if (!isContainerAllowed(cval, allowedItems, phase)) { itemDecision.setValue(false); } }); return itemDecision.booleanValue(); } - private boolean isContainerAllowed(PrismContainerValue cval, Collection allowedItems) { + private boolean isContainerAllowed(PrismContainerValue cval, Collection allowedItems, AuthorizationPhaseType phase) { if (cval.isEmpty()) { // TODO: problem with empty containers such as // orderConstraint in assignment. Skip all @@ -289,18 +289,18 @@ private boolean isContainerAllowed(PrismContainerValue cval, Collection item: cval.getItems()) { ItemPath itemPath = item.getPath(); if (item instanceof PrismContainer) { - if (isInList(itemPath, allowedItems)) { + if (isAllowedItem(itemPath, allowedItems, phase)) { // entire container is allowed. We do not need to go deeper } else { List> subValues = (List)((PrismContainer)item).getValues(); for (PrismContainerValue subValue: subValues) { - if (!isContainerAllowed(subValue, allowedItems)) { + if (!isContainerAllowed(subValue, allowedItems, phase)) { decision = false; } } } } else { - if (!isInList(itemPath, allowedItems)) { + if (!isAllowedItem(itemPath, allowedItems, phase)) { LOGGER.trace(" DENY operation because item {} in the object is not allowed", itemPath); decision = false; } @@ -309,20 +309,20 @@ private boolean isContainerAllowed(PrismContainerValue cval, Collection boolean processAuthorizationDelta(ObjectDelta delta, final Collection allowedItems) { + private boolean processAuthorizationDelta(ObjectDelta delta, final Collection allowedItems, AuthorizationPhaseType phase) { if (delta.isAdd()) { - return processAuthorizationObject(delta.getObjectToAdd(), allowedItems); + return processAuthorizationObject(delta.getObjectToAdd(), allowedItems, phase); } else { for (ItemDelta itemDelta: delta.getModifications()) { ItemPath itemPath = itemDelta.getPath(); if (itemDelta instanceof ContainerDelta) { - if (!isInList(itemPath, allowedItems)) { - if (!processAuthorizationContainerDelta((ContainerDelta)itemDelta, allowedItems)) { + if (!isAllowedItem(itemPath, allowedItems, phase)) { + if (!processAuthorizationContainerDelta((ContainerDelta)itemDelta, allowedItems, phase)) { return false; } } } else { - if (!isInList(itemPath, allowedItems)) { + if (!isAllowedItem(itemPath, allowedItems, phase)) { LOGGER.trace(" DENY operation because item {} in the delta is not allowed", itemPath); return false; } @@ -331,6 +331,17 @@ private boolean processAuthorizationDelta(ObjectDelta return true; } } + + private boolean isAllowedItem(ItemPath itemPath, Collection allowedItems, AuthorizationPhaseType phase) { + return isInList(itemPath, allowedItems) || allowedForExecutionByDefault(itemPath, phase); + } + + private boolean allowedForExecutionByDefault(ItemPath itemPath, AuthorizationPhaseType phase) { + if (!AuthorizationPhaseType.EXECUTION.equals(phase)) { + return false; + } + return isInList(itemPath, AuthorizationConstants.EXECUTION_ITEMS_ALLOWED_BY_DEFAULT); + } private boolean isInList(ItemPath itemPath, Collection allowedItems) { boolean itemAllowed = false; @@ -511,10 +522,28 @@ private boolean isApplicable(SubjectedObjectSelectorType } } if (!found) { - LOGGER.trace(" {}: delegator object spec not applicable for {}, object OID {} because delegator does not match", - autzHumanReadableDesc, desc, object.getOid()); - return false; + if (BooleanUtils.isTrue(delegatorSpec.isAllowInactive())) { + for (AssignmentType objectAssignment: ((UserType)object.asObjectable()).getAssignment()) { + ObjectReferenceType objectAssignmentTargetRef = objectAssignment.getTargetRef(); + if (objectAssignmentTargetRef == null) { + continue; + } + if (principal.getOid().equals(objectAssignmentTargetRef.getOid())) { + if (QNameUtil.match(SchemaConstants.ORG_DEPUTY, objectAssignmentTargetRef.getRelation())) { + found = true; + break; + } + } + } + } + + if (!found) { + LOGGER.trace(" {}: delegator object spec not applicable for {}, object OID {} because delegator does not match", + autzHumanReadableDesc, desc, object.getOid()); + return false; + } } + } } diff --git a/testing/conntest/src/test/resources/ad-ldap-multidomain/resource-chimera.xml b/testing/conntest/src/test/resources/ad-ldap-multidomain/resource-chimera.xml index b5097d22ad7..aef6b2f4bad 100644 --- a/testing/conntest/src/test/resources/ad-ldap-multidomain/resource-chimera.xml +++ b/testing/conntest/src/test/resources/ad-ldap-multidomain/resource-chimera.xml @@ -37,7 +37,7 @@ chimera.ad.evolveum.com 636 - DC=ad,DC=evolveum,DC=com + adBaseDn CN=midpoint,CN=Users,DC=ad,DC=evolveum,DC=com ssl @@ -87,7 +87,7 @@ attributes/dn - CN=Users,DC=ad,DC=evolveum,DC=com + adUsersDn @@ -102,7 +102,7 @@