diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebComponentUtil.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebComponentUtil.java index 3f503d1e85f..99fcc90a2e4 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebComponentUtil.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebComponentUtil.java @@ -581,9 +581,13 @@ public static DropDownChoicePanel createEnumPanel(Class clazz, } public static DropDownChoicePanel createEnumPanel(Class clazz, String id, final IModel model, final Component component, boolean allowNull) { - // final Class clazz = model.getObject().getClass(); - final Object o = model.getObject(); - return new DropDownChoicePanel(id, model, WebComponentUtil.createReadonlyModelFromEnum(clazz), + return createEnumPanel(clazz, id, WebComponentUtil.createReadonlyModelFromEnum(clazz), + model, component, allowNull ); + } + + public static DropDownChoicePanel createEnumPanel(Class clazz, String id, + IModel> choicesList, final IModel model, final Component component, boolean allowNull) { + return new DropDownChoicePanel(id, model, choicesList, new IChoiceRenderer() { @Override diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentCatalogPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentCatalogPanel.java index 9365b4793a1..cf2505c0297 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentCatalogPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentCatalogPanel.java @@ -19,18 +19,11 @@ import com.evolveum.midpoint.gui.api.component.ObjectBrowserPanel; import com.evolveum.midpoint.gui.api.model.LoadableModel; import com.evolveum.midpoint.gui.api.page.PageBase; -import com.evolveum.midpoint.gui.api.util.WebComponentUtil; -import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; import com.evolveum.midpoint.model.api.ModelInteractionService; import com.evolveum.midpoint.model.api.RoleSelectionSpecification; -import com.evolveum.midpoint.model.api.context.*; -import com.evolveum.midpoint.prism.PrismContainerDefinition; import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.delta.DeltaSetTriple; -import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.query.*; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.LoggingUtils; @@ -46,18 +39,14 @@ import com.evolveum.midpoint.web.component.util.SelectableBean; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.midpoint.web.page.admin.orgs.OrgTreePanel; -import com.evolveum.midpoint.web.page.admin.users.dto.TreeStateSet; import com.evolveum.midpoint.web.page.admin.users.dto.UserDtoStatus; -import com.evolveum.midpoint.web.page.self.PageAssignmentShoppingKart; import com.evolveum.midpoint.web.page.self.PageAssignmentsList; -import com.evolveum.midpoint.web.page.self.dto.AssignmentConflictDto; import com.evolveum.midpoint.web.page.self.dto.AssignmentViewType; import com.evolveum.midpoint.web.security.SecurityUtils; import com.evolveum.midpoint.web.session.OrgTreeStateStorage; import com.evolveum.midpoint.web.session.SessionStorage; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang3.EnumUtils; import org.apache.wicket.ajax.AjaxChannel; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.attributes.AjaxRequestAttributes; @@ -72,7 +61,6 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; -import org.apache.wicket.model.util.ListModel; import javax.xml.namespace.QName; import java.util.*; @@ -83,11 +71,11 @@ public class AssignmentCatalogPanel extends BasePanel { private static final long serialVersionUID = 1L; - private static String ID_TREE_PANEL_CONTAINER = "treePanelContainer"; - private static String ID_TREE_PANEL = "treePanel"; - private static String ID_CATALOG_ITEMS_PANEL_CONTAINER = "catalogItemsPanelContainer"; - private static String ID_ASSIGNMENTS_OWNER_NAME = "assignmentsOwnerName"; - private static String ID_CATALOG_ITEMS_PANEL = "catalogItemsPanel"; + private static final String ID_TREE_PANEL_CONTAINER = "treePanelContainer"; + private static final String ID_TREE_PANEL = "treePanel"; + private static final String ID_CATALOG_ITEMS_PANEL_CONTAINER = "catalogItemsPanelContainer"; + private static final String ID_ASSIGNMENTS_OWNER_NAME = "assignmentsOwnerName"; + private static final String ID_CATALOG_ITEMS_PANEL = "catalogItemsPanel"; private static final String ID_CART_BUTTON = "cartButton"; private static final String ID_CART_ITEMS_COUNT = "itemsCount"; private static final String ID_HEADER_PANEL = "headerPanel"; @@ -102,6 +90,7 @@ public class AssignmentCatalogPanel extends BasePane private static final String DOT_CLASS = AssignmentCatalogPanel.class.getName(); private static final Trace LOGGER = TraceManager.getTrace(AssignmentCatalogPanel.class); + private static final String OPERATION_LOAD_ASSIGNMENT_CONSTRAINTS = DOT_CLASS + "loadAssignmentConstraints"; private static final String OPERATION_LOAD_ASSIGNABLE_ROLES = DOT_CLASS + "loadAssignableRoles"; private PageBase pageBase; @@ -111,11 +100,9 @@ public class AssignmentCatalogPanel extends BasePane private IModel viewModel; private IModel> targetUserModel; private ObjectDataProvider objectProvider; - private ListDataProvider listProvider; private int itemsPerRow = 4; private boolean showUserSelectionPopup = true; private List listProviderData; - private AssignmentViewType defaultAssignmentViewType = AssignmentViewType.ROLE_CATALOG_VIEW; List viewTypeList = new ArrayList<>(); public AssignmentCatalogPanel(String id) { @@ -153,7 +140,8 @@ protected void initProvider() { @Override public AssignmentEditorDto createDataObjectWrapper(PrismObject obj) { AssignmentEditorDto dto = AssignmentEditorDto.createDtoFromObject(obj.asObjectable(), UserDtoStatus.ADD, pageBase); - dto.setAlreadyAssigned(isAlreadyAssigned(obj)); + dto.setAlreadyAssigned(isAlreadyAssigned(obj, dto)); + dto.setDefualtAssignmentConstraints(getAssignmentConstraints()); return dto; } @@ -534,9 +522,8 @@ private ObjectQuery createMemberQuery(String oid) { ObjectFilter filter = OrgFilter.createOrg(oid, OrgFilter.Scope.ONE_LEVEL); TypeFilter roleTypeFilter = TypeFilter.createType(RoleType.COMPLEX_TYPE, filter); - TypeFilter orgTypeFilter = TypeFilter.createType(OrgType.COMPLEX_TYPE, filter); TypeFilter serviceTypeFilter = TypeFilter.createType(ServiceType.COMPLEX_TYPE, filter); - ObjectQuery query = ObjectQuery.createObjectQuery(OrFilter.createOr(roleTypeFilter, orgTypeFilter, serviceTypeFilter)); + ObjectQuery query = ObjectQuery.createObjectQuery(OrFilter.createOr(roleTypeFilter, serviceTypeFilter)); return query; } @@ -642,7 +629,9 @@ protected void onSelectPerformed(AjaxRequestTarget target, UserType targetUser) super.onSelectPerformed(target, targetUser); if (targetUserSelection) { pageBase.getSessionStorage().getRoleCatalog().setTargetUser(targetUser.asPrismContainer()); - target.add(getTargetUserContainer()); + AssignmentCatalogPanel.this.addOrReplaceLayout(target, getCatalogItemsPanelContainer()); + target.add(getHeaderPanel()); + target.add(getCatalogItemsPanelContainer()); } else { pageBase.getSessionStorage().getRoleCatalog().setAssignmentsUserOwner(targetUser.asPrismContainer()); AssignmentCatalogPanel.this.addOrReplaceLayout(target, getCatalogItemsPanelContainer()); @@ -689,17 +678,21 @@ public void detach() { }; } - private boolean isAlreadyAssigned(PrismObject obj){ + private boolean isAlreadyAssigned(PrismObject obj, AssignmentEditorDto assignmentDto){ PrismObject user = getTargetUser(); if (user == null || user.asObjectable().getAssignment() == null){ return false; } + boolean isAssigned = false; + List assignedRelationsList = new ArrayList<>(); for (AssignmentType assignment : user.asObjectable().getAssignment()){ if (assignment.getTargetRef() != null && assignment.getTargetRef().getOid().equals(obj.getOid())){ - return true; + isAssigned = true; + assignedRelationsList.add(RelationTypes.getRelationType(assignment.getTargetRef().getRelation())); } } - return false; + assignmentDto.setAssignedRelationsList(assignedRelationsList); + return isAssigned; } private PrismObject getTargetUser(){ @@ -710,5 +703,20 @@ private PrismObject getTargetUser(){ return pageBase.loadUserSelf(pageBase); } + private AssignmentConstraintsType getAssignmentConstraints() { + OperationResult result = new OperationResult(OPERATION_LOAD_ASSIGNMENT_CONSTRAINTS); + SystemConfigurationType systemConfig = null; + try { + systemConfig = pageBase.getModelInteractionService().getSystemConfiguration(result); + } catch (ObjectNotFoundException | SchemaException e) { + LOGGER.error("Error getting system configuration: {}", e.getMessage(), e); + return null; + } + if (systemConfig != null && systemConfig.getRoleManagement() != null) { + return systemConfig.getRoleManagement().getDefaultAssignmentConstraints(); + } + return null; + } + } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorDto.java index 0953cfb6dd4..c37887498f1 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorDto.java @@ -17,6 +17,7 @@ package com.evolveum.midpoint.web.component.assignment; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -95,7 +96,9 @@ public class AssignmentEditorDto extends SelectableBean implements Comparable assignedRelationsList = new ArrayList<>(); //used only for role request functionalityp private Boolean isOrgUnitManager = Boolean.FALSE; private AssignmentType newAssignment; @@ -674,6 +677,22 @@ public void setAlreadyAssigned(boolean alreadyAssigned) { isAlreadyAssigned = alreadyAssigned; } + public AssignmentConstraintsType getDefualtAssignmentConstraints() { + return defualtAssignmentConstraints; + } + + public void setDefualtAssignmentConstraints(AssignmentConstraintsType defualtAssignmentConstraints) { + this.defualtAssignmentConstraints = defualtAssignmentConstraints; + } + + public List getAssignedRelationsList() { + return assignedRelationsList; + } + + public void setAssignedRelationsList(List assignedRelationsList) { + this.assignedRelationsList = assignedRelationsList; + } + public List getPrivilegeLimitationList() { return privilegeLimitationList; } @@ -705,6 +724,76 @@ public void setDelegationOwner(UserType delegationOwner) { this.delegationOwner = delegationOwner; } + public List getNotAssignedRelationsList(){ + List relations = new ArrayList<>(Arrays.asList(RelationTypes.values())); + if (getAssignedRelationsList() == null || getAssignedRelationsList().size() == 0){ + return relations; + } + for (RelationTypes relation : getAssignedRelationsList()){ + if (relations.contains(relation)){ + relations.remove(relation); + } + } + return relations; + } + + public boolean isAssignable() { + if (!isAlreadyAssigned){ + return true; + } + if (defualtAssignmentConstraints == null) { + return true; + } + if (defualtAssignmentConstraints.isAllowSameTarget() && defualtAssignmentConstraints.isAllowSameRelation()){ + return true; + } + if (defualtAssignmentConstraints.isAllowSameTarget() && !defualtAssignmentConstraints.isAllowSameRelation() + && getAssignedRelationsList().size() < RelationTypes.values().length){ + return true; + } + if (!defualtAssignmentConstraints.isAllowSameTarget() && defualtAssignmentConstraints.isAllowSameRelation() + && getAssignedRelationsList().size() < RelationTypes.values().length){ + return true; + } + if (!defualtAssignmentConstraints.isAllowSameTarget() && !defualtAssignmentConstraints.isAllowSameRelation()){ + return false; + } + return false; + } + + public boolean isMultyAssignable(){ + if (defualtAssignmentConstraints == null) { + return true; + } + if (defualtAssignmentConstraints.isAllowSameTarget() && defualtAssignmentConstraints.isAllowSameRelation()){ + return true; + } + return false; + } + + public boolean isSingleAssignable(){ + if (defualtAssignmentConstraints == null) { + return false; + } + if (!defualtAssignmentConstraints.isAllowSameTarget() && !defualtAssignmentConstraints.isAllowSameRelation()){ + return true; + } + return false; + } + + public void setDefaultRelation(){ + if (getTargetRef() == null){ + return; + } + if (!getAssignedRelationsList().contains(RelationTypes.MEMBER)){ + getTargetRef().setRelation(SchemaConstants.ORG_DEFAULT); + } + List availableRelations = getNotAssignedRelationsList(); + if (availableRelations.size() > 0){ + getTargetRef().setRelation(availableRelations.get(0).getRelation()); + } + } + @Override public boolean equals(Object o) { if (this == o) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.java index 9883267c367..d3f908fe8cb 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.java @@ -107,7 +107,7 @@ public class AssignmentEditorPanel extends BasePanel { private static final String ID_DESCRIPTION = "description"; private static final String ID_RELATION_CONTAINER = "relationContainer"; private static final String ID_FOCUS_TYPE = "focusType"; - private static final String ID_RELATION = "relation"; + protected static final String ID_RELATION = "relation"; private static final String ID_RELATION_LABEL = "relationLabel"; private static final String ID_ADMINISTRATIVE_STATUS = "administrativeStatus"; private static final String ID_VALID_FROM = "validFrom"; @@ -417,42 +417,7 @@ public boolean isVisible() { ObjectTypeSelectPanel focusType = new ObjectTypeSelectPanel<>(ID_FOCUS_TYPE, new PropertyModel(getModel(), AssignmentEditorDto.F_FOCUS_TYPE), FocusType.class); body.add(focusType); - - IModel relationModel = new IModel() { - @Override - public RelationTypes getObject() { - if (getModelObject().getTargetRef() == null) { - return RelationTypes.MEMBER; - } - return RelationTypes.getRelationType(getModelObject().getTargetRef().getRelation()); - } - - @Override - public void setObject(RelationTypes newValue) { - ObjectReferenceType ref = getModelObject().getTargetRef(); - if (ref != null){ - ref.setRelation(newValue.getRelation()); - } - } - - @Override - public void detach() { - - } - }; - DropDownChoicePanel relation = WebComponentUtil.createEnumPanel(RelationTypes.class, ID_RELATION, - relationModel, this, false); - relation.setEnabled(getModel().getObject().isEditable()); - relation.setOutputMarkupId(true); - relation.setOutputMarkupPlaceholderTag(true); - relation.add(new VisibleEnableBehaviour() { - - @Override - public boolean isVisible() { - return isCreatingNewAssignment(); - } - }); - relationContainer.add(relation); + addRelationDropDown(relationContainer); Label relationLabel = new Label(ID_RELATION_LABEL, new AbstractReadOnlyModel() { @@ -940,6 +905,83 @@ protected String load() { }; } + private void addRelationDropDown(WebMarkupContainer relationContainer){ + List availableRelations = getModelObject().getNotAssignedRelationsList(); + DropDownChoicePanel relation = WebComponentUtil.createEnumPanel(RelationTypes.class, ID_RELATION, + getModelObject().isMultyAssignable() ? + WebComponentUtil.createReadonlyModelFromEnum(RelationTypes.class) : Model.ofList(availableRelations), + getRelationModel(availableRelations), this, false); + relation.setEnabled(getModel().getObject().isEditable()); + relation.setOutputMarkupId(true); + relation.setOutputMarkupPlaceholderTag(true); + relation.add(new VisibleEnableBehaviour() { + + @Override + public boolean isVisible() { + return isCreatingNewAssignment(); + } + }); + relationContainer.add(relation); + + } + + private IModel getRelationModel(List availableRelations){ + return new IModel() { + @Override + public RelationTypes getObject() { + RelationTypes defaultRelation = RelationTypes.MEMBER; + if (!getModelObject().isMultyAssignable() && + getModelObject().getAssignedRelationsList().contains(defaultRelation)){ + defaultRelation = availableRelations.get(0); + } + if (getModelObject().getTargetRef() == null){ + return defaultRelation; + } + return RelationTypes.getRelationType(getModelObject().getTargetRef().getRelation()); + } + + @Override + public void setObject(RelationTypes relationTypes) { + if (getModelObject().getTargetRef() != null){ + getModelObject().getTargetRef().setRelation(relationTypes.getRelation()); + } + } + + @Override + public void detach() { + + } + }; + } + + + protected IModel getRelationModel(){ + return new IModel() { + private static final long serialVersionUID = 1L; + + @Override + public RelationTypes getObject() { + if (getModelObject().getTargetRef() == null) { + return RelationTypes.MEMBER; + } + return RelationTypes.getRelationType(getModelObject().getTargetRef().getRelation()); + } + + @Override + public void setObject(RelationTypes newValue) { + ObjectReferenceType ref = getModelObject().getTargetRef(); + if (ref != null){ + ref.setRelation(newValue.getRelation()); + } + } + + @Override + public void detach() { + + } + }; + } + private PrismObject getTargetObject(AssignmentEditorDto dto) throws ObjectNotFoundException, SchemaException, SecurityViolationException, CommunicationException, ConfigurationException { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentTablePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentTablePanel.java index d7bafa41ab9..1abcc8bd934 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentTablePanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentTablePanel.java @@ -72,6 +72,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import org.w3c.dom.Attr; /** * @author shood @@ -128,7 +129,7 @@ private void initLayout(IModel labelText) { @Override protected void populateItem(ListItem item) { - AssignmentTablePanel.this.populateItem(item); + AssignmentTablePanel.this.populateAssignmentDetailsPanel(item); } }; list.setOutputMarkupId(true); @@ -167,7 +168,7 @@ public boolean isVisible(){ } - protected void populateItem(ListItem item){ + protected void populateAssignmentDetailsPanel(ListItem item){ AssignmentEditorPanel editor = new AssignmentEditorPanel(ID_ROW, item.getModel()){ @Override protected boolean ignoreMandatoryAttributes(){ @@ -176,7 +177,11 @@ protected boolean ignoreMandatoryAttributes(){ }; item.add(editor); - editor.add(AttributeModifier.append("class", new AbstractReadOnlyModel() { + editor.add(getClassModifier(item)); + } + + protected AttributeModifier getClassModifier(ListItem item){ + return AttributeModifier.append("class", new AbstractReadOnlyModel() { private static final long serialVersionUID = 1L; @Override @@ -189,7 +194,7 @@ public String getObject() { return GuiStyleConstants.CLASS_OBJECT_RESOURCE_BOX_THIN_CSS_CLASSES; } } - })); + }); } protected List createAssignmentMenu() { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/ShoppingCartEditorPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/ShoppingCartEditorPanel.java index fc5f0aa4405..cb57a877ec2 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/ShoppingCartEditorPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/ShoppingCartEditorPanel.java @@ -16,13 +16,21 @@ package com.evolveum.midpoint.web.component.assignment; +import com.evolveum.midpoint.gui.api.util.WebComponentUtil; +import com.evolveum.midpoint.web.component.input.DropDownChoicePanel; +import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import org.apache.wicket.AttributeModifier; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.model.AbstractReadOnlyModel; import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; +import java.util.ArrayList; +import java.util.List; + /** * Created by honchar. */ diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.java index e8756e8d3e9..4b7e46d7ce4 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.java @@ -18,17 +18,12 @@ import com.evolveum.midpoint.gui.api.GuiStyleConstants; import com.evolveum.midpoint.gui.api.component.BasePanel; import com.evolveum.midpoint.gui.api.page.PageBase; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.assignment.*; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.midpoint.web.page.self.PageAssignmentDetails; import com.evolveum.midpoint.web.session.RoleCatalogStorage; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentConstraintsType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.behavior.AttributeAppender; @@ -36,6 +31,7 @@ import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.repeater.RepeatingView; import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; import java.util.ArrayList; import java.util.List; @@ -61,7 +57,6 @@ public class MultiButtonTable extends BasePanel> { private static final String DOT_CLASS = AssignmentCatalogPanel.class.getName(); private static final Trace LOGGER = TraceManager.getTrace(AssignmentCatalogPanel.class); - private static final String OPERATION_LOAD_ASSIGNMENT_CONSTRAINTS = DOT_CLASS + "loadAssignmentConstraints"; private String addToCartLinkIcon = "fa fa-times-circle fa-lg text-danger"; private String detailsLinkIcon = "fa fa-arrow-circle-right"; @@ -219,37 +214,14 @@ public boolean isEnabled(){ } private boolean canAssign(final AssignmentEditorDto assignment) { - AssignmentConstraintsType assignmentConstraints = getAssignmentConstraints(); - if (assignmentConstraints == null) { - return true; - } - // TODO -// return !(AssignmentMultiplicityType.SINGLE.equals(getAssignmentMultiplicity()) -// && assignment.isAlreadyAssigned()); - return true; + return assignment.isAssignable(); } private void assignmentDetailsPerformed(final AssignmentEditorDto assignment, AjaxRequestTarget target){ if (!plusIconClicked) { - IModel assignmentModel = new IModel() { - @Override - public AssignmentEditorDto getObject() { - assignment.setMinimized(false); - assignment.setSimpleView(true); - return assignment; - } - - @Override - public void setObject(AssignmentEditorDto assignmentEditorDto) { - - } - - @Override - public void detach() { - - } - }; - setResponsePage(new PageAssignmentDetails(assignmentModel)); + assignment.setMinimized(false); + assignment.setSimpleView(true); + pageBase.navigateToNext(new PageAssignmentDetails(Model.of(assignment))); } else { plusIconClicked = false; } @@ -284,30 +256,15 @@ private String getBackgroundClass(AssignmentEditorDto dto){ private void addAssignmentPerformed(AssignmentEditorDto assignment, AjaxRequestTarget target){ plusIconClicked = true; - RoleCatalogStorage storage = getPageBase().getSessionStorage().getRoleCatalog(); + RoleCatalogStorage storage = pageBase.getSessionStorage().getRoleCatalog(); if (storage.getAssignmentShoppingCart() == null){ storage.setAssignmentShoppingCart(new ArrayList()); } - List assignmentsToAdd = storage.getAssignmentShoppingCart(); - assignmentsToAdd.add(assignment); - storage.setAssignmentShoppingCart(assignmentsToAdd); + assignment.setDefaultRelation(); + storage.getAssignmentShoppingCart().add(assignment); AssignmentCatalogPanel parent = MultiButtonTable.this.findParent(AssignmentCatalogPanel.class); parent.reloadCartButton(target); } - private AssignmentConstraintsType getAssignmentConstraints() { - OperationResult result = new OperationResult(OPERATION_LOAD_ASSIGNMENT_CONSTRAINTS); - SystemConfigurationType systemConfig = null; - try { - systemConfig = pageBase.getModelInteractionService().getSystemConfiguration(result); - } catch (ObjectNotFoundException | SchemaException e) { - LOGGER.error("Error getting system configuration: {}", e.getMessage(), e); - return null; - } - if (systemConfig != null && systemConfig.getRoleManagement() != null) { - return systemConfig.getRoleManagement().getDefaultAssignmentConstraints(); - } - return null; - } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageUser.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageUser.java index 9894552ed4a..6f133790365 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageUser.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageUser.java @@ -197,7 +197,7 @@ public WebMarkupContainer createPanel(String panelId) { private static final long serialVersionUID = 1L; @Override - public void populateItem(ListItem item) { + public void populateAssignmentDetailsPanel(ListItem item) { DelegationEditorPanel editor = new DelegationEditorPanel(ID_ROW, item.getModel(), false, privilegesList, PageUser.this); item.add(editor); @@ -330,7 +330,7 @@ public WebMarkupContainer createPanel(String panelId) { private static final long serialVersionUID = 1L; @Override - public void populateItem(ListItem item) { + public void populateAssignmentDetailsPanel(ListItem item) { DelegationEditorPanel editor = new DelegationEditorPanel(ID_ROW, item.getModel(), true, privilegesList, PageUser.this); item.add(editor); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageUserHistory.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageUserHistory.java index f77803504bf..100c1825550 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageUserHistory.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageUserHistory.java @@ -215,7 +215,7 @@ public WebMarkupContainer createPanel(String panelId) { private static final long serialVersionUID = 1L; @Override - public void populateItem(ListItem item) { + public void populateAssignmentDetailsPanel(ListItem item) { DelegationEditorPanel editor = new DelegationEditorPanel(ID_ROW, item.getModel(), true, new ArrayList(), PageUserHistory.this); item.add(editor); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentDetails.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentDetails.java index 17eb8d4b64e..6b774388cb4 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentDetails.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentDetails.java @@ -70,9 +70,8 @@ public void onClick(AjaxRequestTarget target) { if (storage.getAssignmentShoppingCart() == null){ storage.setAssignmentShoppingCart(new ArrayList()); } - List assignmentsToAdd = storage.getAssignmentShoppingCart(); - assignmentsToAdd.add(assignmentModel.getObject()); - storage.setAssignmentShoppingCart(assignmentsToAdd); + AssignmentEditorDto dto = assignmentModel.getObject(); + storage.getAssignmentShoppingCart().add(dto); redirectBack(); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentsList.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentsList.html index 17d2362c174..bf5e7f45812 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentsList.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentsList.html @@ -22,6 +22,7 @@
+

diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentsList.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentsList.java index aed411a2172..de1f622f039 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentsList.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentsList.java @@ -19,7 +19,9 @@ import com.evolveum.midpoint.web.component.AjaxButton; import com.evolveum.midpoint.web.component.AjaxSubmitButton; import com.evolveum.midpoint.web.component.assignment.AssignmentEditorDto; +import com.evolveum.midpoint.web.component.assignment.AssignmentEditorPanel; import com.evolveum.midpoint.web.component.assignment.AssignmentTablePanel; +import com.evolveum.midpoint.web.component.assignment.ShoppingCartEditorPanel; import com.evolveum.midpoint.web.component.form.Form; import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem; import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItemAction; @@ -33,6 +35,7 @@ import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.markup.html.form.TextArea; +import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; @@ -85,7 +88,7 @@ public void initLayout() { mainForm.setOutputMarkupId(true); add(mainForm); - AssignmentTablePanel panel = new AssignmentTablePanel(ID_ASSIGNMENT_TABLE_PANEL, + AssignmentTablePanel panel = new AssignmentTablePanel(ID_ASSIGNMENT_TABLE_PANEL, createStringResource("FocusType.assignment"), assignmentsModel){ @Override protected List createAssignmentMenu() { @@ -101,7 +104,6 @@ public void onClick(AjaxRequestTarget target) { }); items.add(item); return items; - } }; mainForm.add(panel); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointGuiAuthorizationEvaluator.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointGuiAuthorizationEvaluator.java index df7cf9af7b1..dc9f3c75910 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointGuiAuthorizationEvaluator.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointGuiAuthorizationEvaluator.java @@ -21,6 +21,7 @@ import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.security.api.ItemSecurityDecisions; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.security.api.ObjectSecurityConstraints; import com.evolveum.midpoint.security.api.OwnerResolver; @@ -33,6 +34,7 @@ import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.application.DescriptorLoader; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationPhaseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; @@ -211,4 +213,11 @@ public T runAs(Producer producer, PrismObject user) throws Sche public T runPrivileged(Producer producer) { return securityEnforcer.runPrivileged(producer); } + + @Override + public ItemSecurityDecisions getAllowedRequestAssignmentItems( + MidPointPrincipal midPointPrincipal, PrismObject object, PrismObject target, + OwnerResolver ownerResolver) throws SchemaException { + return securityEnforcer.getAllowedRequestAssignmentItems(midPointPrincipal, object, target, ownerResolver); + } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/RoleCatalogStorage.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/RoleCatalogStorage.java index 9c514d929c0..3d77751423b 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/RoleCatalogStorage.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/RoleCatalogStorage.java @@ -146,7 +146,10 @@ public void setConflictsList(List conflictsList) { } public List getAssignmentShoppingCart() { - return assignmentShoppingCart == null ? new ArrayList() : assignmentShoppingCart; + if (assignmentShoppingCart == null){ + assignmentShoppingCart = new ArrayList<>(); + } + return assignmentShoppingCart; } public void setAssignmentShoppingCart(List assignmentShoppingCart) { diff --git a/gui/admin-gui/src/main/resources/initial-objects/120-security-policy.xml b/gui/admin-gui/src/main/resources/initial-objects/015-security-policy.xml similarity index 100% rename from gui/admin-gui/src/main/resources/initial-objects/120-security-policy.xml rename to gui/admin-gui/src/main/resources/initial-objects/015-security-policy.xml diff --git a/gui/admin-gui/src/main/resources/localization/Midpoint.properties b/gui/admin-gui/src/main/resources/localization/Midpoint.properties index 09999e076c1..a99be7490a5 100644 --- a/gui/admin-gui/src/main/resources/localization/Midpoint.properties +++ b/gui/admin-gui/src/main/resources/localization/Midpoint.properties @@ -3405,8 +3405,8 @@ PageAssignmentConflicts.back=Back PageAssignmentConflicts.submit=Submit AssignmentCatalogPanel.selectTargetUser=Select target user AssignmentCatalogPanel.selectAssignmentsUserOwner=Select assignments user owner -AssignmentCatalogPanel.requestForMe=Request for me -AssignmentCatalogPanel.requestFor=Request for +AssignmentCatalogPanel.requestForMe=Target user: me +AssignmentCatalogPanel.requestFor=Target user: AssignmentCatalogPanel.assignmentsOwner={0}'s assignments MultiButtonPanel.plusIconTitle=Add item to shopping cart MultiButtonPanel.assignmentDetailsPopupTitle=Assignment details @@ -3418,6 +3418,7 @@ PageAssignmentDetails.addToCartButton=Add to cart PageAssignmentsList.submitButton=Submit PageAssignmentsList.resolveConflicts=Resolve conflicts PageAssignmentsList.commentHere=Comment here... +PageAssignmentsList.requestComment=Request comment (optional) AssignmentShoppingCartPanel.treeTitle=Role catalog AssignmentViewType.ROLE_CATALOG_VIEW=Role catalog view AssignmentViewType.ROLE_TYPE=All roles view diff --git a/gui/admin-gui/src/main/resources/localization/Midpoint_en.properties b/gui/admin-gui/src/main/resources/localization/Midpoint_en.properties index 4dada181b92..e2ef3bf6375 100644 --- a/gui/admin-gui/src/main/resources/localization/Midpoint_en.properties +++ b/gui/admin-gui/src/main/resources/localization/Midpoint_en.properties @@ -3361,8 +3361,8 @@ PageAssignmentConflicts.back=Back PageAssignmentConflicts.submit=Submit AssignmentCatalogPanel.selectTargetUser=Select target user AssignmentCatalogPanel.selectAssignmentsUserOwner=Select assignments user owner -AssignmentCatalogPanel.requestForMe=Request for me -AssignmentCatalogPanel.requestFor=Request for +AssignmentCatalogPanel.requestForMe=Target user: me +AssignmentCatalogPanel.requestFor=Target user: AssignmentCatalogPanel.assignmentsOwner={0}'s assignments MultiButtonPanel.plusIconTitle=Add item to shopping cart MultiButtonPanel.assignmentDetailsPopupTitle=Assignment details diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainer.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainer.java index 7333d70a2cb..5920b8241c3 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainer.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainer.java @@ -456,25 +456,26 @@ public Item findItem(It } } - > I findCreateItem(ItemPath itemPath, Class type, ID itemDefinition, boolean create) throws SchemaException { + public boolean containsItem(ItemPath itemPath, boolean acceptEmptyItem) throws SchemaException { if (itemPath == null || itemPath.isEmpty()) { throw new IllegalArgumentException("Empty path specified"); } - - if (itemPath.isEmpty()) { - // This is the end ... - if (type.isAssignableFrom(getClass())) { - return (I) this; - } else { - if (create) { - throw new IllegalStateException("The " + type.getSimpleName() + " " + getElementName() + " cannot be created because " - + this.getClass().getSimpleName() + " with the same name exists"); - } else { - return null; - } + + ItemPath rest = ItemPath.pathRestStartingWithName(itemPath); + for (PrismContainerValue value: getValues()) { + if (value.containsItem(rest, acceptEmptyItem)) { + return true; } } + return false; + } + + > I findCreateItem(ItemPath itemPath, Class type, ID itemDefinition, boolean create) throws SchemaException { + if (itemPath == null || itemPath.isEmpty()) { + throw new IllegalArgumentException("Empty path specified"); + } + IdItemPathSegment idSegment = ItemPath.getFirstIdSegment(itemPath); PrismContainerValue cval = findValue(idSegment); if (cval == null) { diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainerValue.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainerValue.java index c834c85b94d..464b499f1c1 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainerValue.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainerValue.java @@ -634,6 +634,29 @@ public > return findItem(itemDefinition.getName(), type); } + public boolean containsItem(ItemPath propPath, boolean acceptEmptyItem) throws SchemaException { + ItemPathSegment first = propPath.first(); + if (!(first instanceof NameItemPathSegment)) { + throw new IllegalArgumentException("Attempt to lookup item using a non-name path "+propPath+" in "+this); + } + QName subName = ((NameItemPathSegment)first).getName(); + ItemPath rest = propPath.rest(); + Item item = findItemByQName(subName); + if (item != null) { + if (rest.isEmpty()) { + return (acceptEmptyItem || !item.isEmpty()); + } else { + // Go deeper + if (item instanceof PrismContainer) { + return ((PrismContainer)item).containsItem(rest, acceptEmptyItem); + } else { + return (acceptEmptyItem || !item.isEmpty()); + } + } + } + + return false; + } // Expects that "self" path is NOT present in propPath @SuppressWarnings("unchecked") diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ObjectDelta.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ObjectDelta.java index a0c498c8535..437110a12ea 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ObjectDelta.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ObjectDelta.java @@ -766,6 +766,10 @@ public ReferenceDelta createReferenceModification(ItemPath path, PrismReferenceD return addModification(referenceDelta); } + public ContainerDelta createContainerModification(QName qname) { + return createContainerModification(new ItemPath(qname)); + } + public ContainerDelta createContainerModification(ItemPath path) { PrismObjectDefinition objDef = getPrismContext().getSchemaRegistry().findObjectDefinitionByCompileTimeClass(getObjectTypeClass()); PrismContainerDefinition propDef = objDef.findContainerDefinition(path); diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/util/PrismAsserts.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/util/PrismAsserts.java index a49c329f33c..6cb32efc1a6 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/util/PrismAsserts.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/util/PrismAsserts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Evolveum + * Copyright (c) 2010-2017 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -480,6 +480,14 @@ public static void assertNoItemDelta(ObjectDelta objectDelta, ItemPath itemPa assert !objectDelta.hasItemDelta(itemPath) : "Delta for item "+itemPath+" present while not expecting it"; } + public static void assertPropertyDelta(PropertyDelta delta, T[] expectedOldValues, T[] expectedAddValues, T[] expectedDeleteValues, T[] expectedReplaceValues) { + assertNotNull("No delta",delta); + assertSet("delta "+delta, "old", delta.getEstimatedOldValues(), expectedOldValues); + assertSet("delta "+delta, "add", delta.getValuesToAdd(), expectedAddValues); + assertSet("delta "+delta, "delete", delta.getValuesToDelete(), expectedDeleteValues); + assertSet("delta "+delta, "replace", delta.getValuesToReplace(), expectedReplaceValues); + } + public static ContainerDelta assertContainerAddGetContainerDelta(ObjectDelta objectDelta, QName name) { return assertContainerAddGetContainerDelta(objectDelta, new ItemPath(name)); } @@ -846,21 +854,25 @@ public static void assertValues(String message, Collection void assertValues(String message, MatchingRule matchingRule, Collection> actualPValues, T... expectedValues) throws SchemaException { - assertNotNull("Null set in " + message, actualPValues); - if (expectedValues.length != actualPValues.size()) { - fail("Wrong number of values in " + message+ "; expected "+expectedValues.length+" (real values) " - +PrettyPrinter.prettyPrint(expectedValues)+"; has "+actualPValues.size()+" (pvalues) "+actualPValues); - } - for (PrismPropertyValue actualPValue: actualPValues) { - boolean found = false; - for (T value: expectedValues) { - if (PrismUtil.equals(value, actualPValue.getValue(), matchingRule)) { - found = true; - } + if (expectedValues == null) { + assertNull("Unexpected set in" +message+": "+actualPValues, actualPValues); + } else { + assertNotNull("Null set in " + message, actualPValues); + if (expectedValues.length != actualPValues.size()) { + fail("Wrong number of values in " + message+ "; expected "+expectedValues.length+" (real values) " + +PrettyPrinter.prettyPrint(expectedValues)+"; has "+actualPValues.size()+" (pvalues) "+actualPValues); } - if (!found) { - fail("Unexpected value "+actualPValue+" in " + message + "; expected (real values) " - +PrettyPrinter.prettyPrint(expectedValues)+"; has (pvalues) "+actualPValues); + for (PrismPropertyValue actualPValue: actualPValues) { + boolean found = false; + for (T value: expectedValues) { + if (PrismUtil.equals(value, actualPValue.getValue(), matchingRule)) { + found = true; + } + } + if (!found) { + fail("Unexpected value "+actualPValue+" in " + message + "; expected (real values) " + +PrettyPrinter.prettyPrint(expectedValues)+"; has (pvalues) "+actualPValues); + } } } } @@ -1050,6 +1062,10 @@ public static void assertRefFilter(ObjectFilter objectFilter, QName expectedFilt static void assertNotNull(String string, Object object) { assert object != null : string; } + + static void assertNull(String string, Object object) { + assert object == null : string; + } private static void assertTrue(String message, boolean test) { assert test : message; 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 683d6c49a43..afd10d41652 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 @@ -11202,13 +11202,13 @@ - + Constraint all assignments that have the same target. I.e. multiple assignments of the same (abstract) role. - If prohibitSameTarget=false then multiple assignments of the same role are allowed. - If prohibitSameTarget=true then multiple assignments of the same role are prohibited. + If allowSameTarget=true then multiple assignments of the same role are allowed. + If allowSameTarget=false then multiple assignments of the same role are prohibited. (but see also other constraints in this type) @@ -11216,13 +11216,12 @@ - + Constraint all assignments that have the same relation. - E.g. if prohibitSameTarget=true and prohibitSameRelation=false then multiple assignments + E.g. if allowSameTarget=true and allowSameRelation=false then multiple assignments of the same role are allowed as long as they have different relation. - If prohibitSameTarget=true and prohibitSameRelation=false 3.6 diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java index 8a6a37d4a1c..05d9680b53b 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Evolveum + * Copyright (c) 2010-2017 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.statistics.ConnectorOperationalStatus; +import com.evolveum.midpoint.security.api.ItemSecurityDecisions; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.DisplayableValue; import com.evolveum.midpoint.util.exception.*; @@ -53,6 +54,7 @@ public interface ModelInteractionService { static final String PREVIEW_CHANGES = CLASS_NAME_WITH_DOT + "previewChanges"; static final String GET_EDIT_OBJECT_DEFINITION = CLASS_NAME_WITH_DOT + "getEditObjectDefinition"; static final String GET_EDIT_SHADOW_DEFINITION = CLASS_NAME_WITH_DOT + "getEditShadowDefinition"; + static final String GET_ALLOWED_REQUEST_ASSIGNMENT_ITEMS = CLASS_NAME_WITH_DOT + "getAllowedRequestAssignmentItems"; static final String GET_ASSIGNABLE_ROLE_SPECIFICATION = CLASS_NAME_WITH_DOT + "getAssignableRoleSpecification"; static final String GET_CREDENTIALS_POLICY = CLASS_NAME_WITH_DOT + "getCredentialsPolicy"; static final String GET_AUTHENTICATIONS_POLICY = CLASS_NAME_WITH_DOT + "getAuthenticationsPolicy"; @@ -63,6 +65,8 @@ public interface ModelInteractionService { static final String MERGE_OBJECTS_PREVIEW_DELTA = CLASS_NAME_WITH_DOT + "mergeObjectsPreviewDelta"; static final String MERGE_OBJECTS_PREVIEW_OBJECT = CLASS_NAME_WITH_DOT + "mergeObjectsPreviewObject"; + + /** * Computes the most likely changes triggered by the provided delta. The delta may be any change of any object, e.g. * add of a user or change of a shadow. The resulting context will sort that out to "focus" and "projection" as needed. @@ -137,6 +141,15 @@ ModelContext previewChanges( * @param focus Object of the operation. The object (usually user) to whom the roles should be assigned. */ RoleSelectionSpecification getAssignableRoleSpecification(PrismObject focus, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, ConfigurationException; + + /** + * Returns decisions for individual items for "assign" authorization. This is usually applicable to assignment parameters. + * The decisions are evaluated using the security context of a currently logged-in user. + * + * @param object object of the operation (user) + * @param target target of the operation (role, org, service that is being assigned) + */ + ItemSecurityDecisions getAllowedRequestAssignmentItems(PrismObject object, PrismObject target) throws SchemaException, SecurityViolationException; SecurityPolicyType getSecurityPolicy(PrismObject user, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException; @@ -206,7 +219,7 @@ AccessCertificationConfigurationType getCertificationConfiguration(OperationResu * @return true if the password matches, false otherwise */ boolean checkPassword(String userOid, ProtectedStringType password, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException; - + // TEMPORARY List visualizeDeltas(List> deltas, Task task, OperationResult result) throws SchemaException; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java index cbf81dafb22..cf71e387305 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java @@ -62,6 +62,9 @@ import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.schema.statistics.ConnectorOperationalStatus; import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.security.api.Authorization; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.security.api.ItemSecurityDecisions; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.security.api.ObjectSecurityConstraints; import com.evolveum.midpoint.security.api.SecurityEnforcer; @@ -360,6 +363,9 @@ public RefinedObjectClassDefinition getEditObjectClassDefinition(PrismObject ItemSecurityDecisions getAllowedRequestAssignmentItems(PrismObject object, PrismObject target) throws SchemaException, SecurityViolationException { + return securityEnforcer.getAllowedRequestAssignmentItems(securityEnforcer.getPrincipal(), object, target, null); + } @Override public Collection> getActionUrls() { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Clockwork.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Clockwork.java index 1fb967f7cd4..d11292bc90e 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Clockwork.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Clockwork.java @@ -1115,7 +1115,7 @@ private AuthorizationDecisionType evaluateCredentialDecision(ObjectSecurityConst ModelAuthorizationAction.CHANGE_CREDENTIALS.getUrl(), AuthorizationPhaseType.REQUEST); } - private void authorizeAssignmentRequest(String assignActionUrl, PrismObject object, + private void authorizeAssignmentRequest(String assignActionUrl, PrismObject object, OwnerResolver ownerResolver, Collection evaluatedAssignments, boolean prohibitPolicies, OperationResult result) throws SecurityViolationException, SchemaException { if (evaluatedAssignments == null) { return; @@ -1128,13 +1128,17 @@ private void authorizeAssignmentRequest(String assignActio securityEnforcer.failAuthorization("with assignment because of policies in the assignment", AuthorizationPhaseType.REQUEST, object, null, target, result); } } - if (securityEnforcer.isAuthorized(assignActionUrl, AuthorizationPhaseType.REQUEST, object, null, target, ownerResolver)) { + ObjectDelta assignmentObjectDelta = object.createModifyDelta(); + ContainerDelta assignmentDelta = assignmentObjectDelta.createContainerModification(FocusType.F_ASSIGNMENT); + // We do not care if this is add or delete. All that matters for authorization is that it is in a delta. + assignmentDelta.addValuesToAdd(evaluatedAssignment.getAssignmentType().asPrismContainerValue().clone()); + if (securityEnforcer.isAuthorized(assignActionUrl, AuthorizationPhaseType.REQUEST, object, assignmentObjectDelta, target, ownerResolver)) { LOGGER.trace("Operation authorized with {} authorization", assignActionUrl); continue; } QName relation = evaluatedAssignment.getRelation(); if (ObjectTypeUtil.isDelegationRelation(relation)) { - if (securityEnforcer.isAuthorized(ModelAuthorizationAction.DELEGATE.getUrl(), AuthorizationPhaseType.REQUEST, object, null, target, ownerResolver)) { + if (securityEnforcer.isAuthorized(ModelAuthorizationAction.DELEGATE.getUrl(), AuthorizationPhaseType.REQUEST, object, assignmentObjectDelta, target, ownerResolver)) { LOGGER.trace("Operation authorized with {} authorization", ModelAuthorizationAction.DELEGATE.getUrl()); continue; } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java index 1bbfc61a9a3..3b7ce49d567 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java @@ -419,6 +419,13 @@ ItemDelta consolidateTripleToDelta( LOGGER.trace("Existing values for item {} in {}, weak mapping processing skipped", new Object[]{itemPath, contextDescription}); } + + if (itemExisting != null) { + List existingValues = itemExisting.getValues(); + if (existingValues != null) { + itemDelta.setEstimatedOldValues(PrismValue.cloneCollection(existingValues)); + } + } return itemDelta; diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java index 56254d3e8b5..2c9207b83b7 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java @@ -163,6 +163,12 @@ public class AbstractConfiguredModelIntegrationTest extends AbstractModelIntegra protected static final String RESOURCE_DUMMY_BLACK_OID = "10000000-0000-0000-0000-000000000305"; protected static final String RESOURCE_DUMMY_BLACK_NAME = "black"; protected static final String RESOURCE_DUMMY_BLACK_NAMESPACE = MidPointConstants.NS_RI; + + // Black dummy resource for testing tolerant attributes + protected static final File RESOURCE_DUMMY_RELATIVE_FILE = new File(COMMON_DIR, "resource-dummy-relative.xml"); + protected static final String RESOURCE_DUMMY_RELATIVE_OID = "adcd4654-0f15-11e7-8337-0bdf60ad7bcd"; + protected static final String RESOURCE_DUMMY_RELATIVE_NAME = "relative"; + protected static final String RESOURCE_DUMMY_RELATIVE_NAMESPACE = MidPointConstants.NS_RI; // Orange dummy resource for testing associations with resource-provided referential integrity // It also have very little outbound expressions and it has some strange inbound expressions. @@ -195,7 +201,7 @@ public class AbstractConfiguredModelIntegrationTest extends AbstractModelIntegra protected static final String ROLE_PIRATE_DESCRIPTION = "Scurvy Pirates"; protected static final String ROLE_PIRATE_TITLE = "Bloody Pirate"; protected static final String ROLE_PIRATE_WEAPON = "cutlass"; - + protected static final File ROLE_CARIBBEAN_PIRATE_FILE = new File(COMMON_DIR, "role-caribbean-pirate.xml"); protected static final String ROLE_CARIBBEAN_PIRATE_OID = "0719ec66-edd9-11e6-bd70-03a74157ff9e"; @@ -204,6 +210,10 @@ public class AbstractConfiguredModelIntegrationTest extends AbstractModelIntegra protected static final String ROLE_PIRATE_GREEN_NAME = "Pirate Green"; protected static final String ROLE_PIRATE_GREEN_DESCRIPTION = "Scurvy Pirates"; + protected static final File ROLE_PIRATE_RELATIVE_FILE = new File(COMMON_DIR, "role-pirate-relative.xml"); + protected static final String ROLE_PIRATE_RELATIVE_OID = "4a579cd0-0f17-11e7-967c-130ecd6fb7dc"; + protected static final String ROLE_PIRAT_RELATIVEE_NAME = "Relative Pirate"; + protected static final File ROLE_BUCCANEER_GREEN_FILE = new File(COMMON_DIR, "role-buccaneer-green.xml"); protected static final String ROLE_BUCCANEER_GREEN_OID = "12345678-d34d-b33f-f00d-555555558888"; protected static final String ROLE_BUCCANEER_GREEN_NAME = "Bucaneers Green"; diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractInitializedModelIntegrationTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractInitializedModelIntegrationTest.java index 332b1515e10..50b678c2e3c 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractInitializedModelIntegrationTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractInitializedModelIntegrationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Evolveum + * Copyright (c) 2010-2017 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -160,6 +160,9 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti initDummyResourcePirate(RESOURCE_DUMMY_BLACK_NAME, RESOURCE_DUMMY_BLACK_FILE, RESOURCE_DUMMY_BLACK_OID, initTask, initResult); + initDummyResourcePirate(RESOURCE_DUMMY_RELATIVE_NAME, + RESOURCE_DUMMY_RELATIVE_FILE, RESOURCE_DUMMY_RELATIVE_OID, initTask, initResult); + dummyResourceCtlBlue = DummyResourceContoller.create(RESOURCE_DUMMY_BLUE_NAME, resourceDummyBlue); dummyResourceCtlBlue.extendSchemaPirate(); dummyResourceBlue = dummyResourceCtlBlue.getDummyResource(); @@ -253,6 +256,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti // Roles repoAddObjectFromFile(ROLE_PIRATE_FILE, initResult); repoAddObjectFromFile(ROLE_PIRATE_GREEN_FILE, initResult); + repoAddObjectFromFile(ROLE_PIRATE_RELATIVE_FILE, initResult); repoAddObjectFromFile(ROLE_CARIBBEAN_PIRATE_FILE, initResult); repoAddObjectFromFile(ROLE_BUCCANEER_GREEN_FILE, initResult); repoAddObjectFromFile(ROLE_NICE_PIRATE_FILENAME, initResult); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java index 6b151f9a74d..876379f9875 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestAudit.java @@ -77,7 +77,7 @@ public class TestAudit extends AbstractInitializedModelIntegrationTest { public static final File TEST_DIR = new File("src/test/resources/audit"); - public static final int INITIAL_NUMBER_OF_AUDIT_RECORDS = 24; + public static final int INITIAL_NUMBER_OF_AUDIT_RECORDS = 26; private XMLGregorianCalendar initialTs; private XMLGregorianCalendar jackKidTs; diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPreviewChanges.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPreviewChanges.java index cb065e1674a..0e60492f21f 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPreviewChanges.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestPreviewChanges.java @@ -36,6 +36,7 @@ import org.testng.AssertJUnit; import org.testng.annotations.Test; +import com.evolveum.icf.dummy.resource.DummyAccount; import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.api.context.ModelContext; @@ -79,6 +80,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationPhaseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.RichHyperlinkType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; @@ -112,6 +114,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti initDummyResourcePirate(RESOURCE_DUMMY_LEMON_NAME, RESOURCE_DUMMY_LEMON_FILE, RESOURCE_DUMMY_LEMON_OID, initTask, initResult); + } @Test @@ -490,8 +493,8 @@ public void test150GetGuybrushRefinedObjectClassDef() throws Exception { } @Test - public void test200ModifyUserDeleteAccount() throws Exception { - final String TEST_NAME = "test200ModifyUserDeleteAccount"; + public void test200ModifyUserGuybrushDeleteAccount() throws Exception { + final String TEST_NAME = "test200ModifyUserGuybrushDeleteAccount"; TestUtil.displayTestTile(this, TEST_NAME); // GIVEN @@ -510,9 +513,11 @@ public void test200ModifyUserDeleteAccount() throws Exception { display("Input deltas: ", deltas); // WHEN + TestUtil.displayWhen(TEST_NAME); ModelContext modelContext = modelInteractionService.previewChanges(deltas, new ModelExecuteOptions(), task, result); // THEN + TestUtil.displayThen(TEST_NAME); display("Preview context", modelContext); assertNotNull("Null model context", modelContext); @@ -537,8 +542,8 @@ public void test200ModifyUserDeleteAccount() throws Exception { } @Test - public void test210AddAccount() throws Exception { - final String TEST_NAME = "test210AddAccount"; + public void test210GuybrushAddAccount() throws Exception { + final String TEST_NAME = "test210GuybrushAddAccount"; TestUtil.displayTestTile(this, TEST_NAME); // GIVEN @@ -552,9 +557,11 @@ public void test210AddAccount() throws Exception { display("Input deltas: ", deltas); // WHEN + TestUtil.displayWhen(TEST_NAME); ModelContext modelContext = modelInteractionService.previewChanges(deltas, new ModelExecuteOptions(), task, result); // THEN + TestUtil.displayThen(TEST_NAME); display("Preview context", modelContext); assertNotNull("Null model context", modelContext); @@ -586,8 +593,8 @@ public void test210AddAccount() throws Exception { } @Test - public void test221ModifyUserAddAccountRef() throws Exception { - final String TEST_NAME = "test221ModifyUserAddAccountRef"; + public void test212ModifyUserAddAccountRef() throws Exception { + final String TEST_NAME = "test212ModifyUserAddAccountRef"; TestUtil.displayTestTile(this, TEST_NAME); // GIVEN @@ -603,9 +610,11 @@ public void test221ModifyUserAddAccountRef() throws Exception { display("Input deltas: ", userDelta); // WHEN + TestUtil.displayWhen(TEST_NAME); ModelContext modelContext = modelInteractionService.previewChanges(deltas, new ModelExecuteOptions(), task, result); // THEN + TestUtil.displayThen(TEST_NAME); display("Preview context", modelContext); assertNotNull("Null model context", modelContext); @@ -637,6 +646,562 @@ public void test221ModifyUserAddAccountRef() throws Exception { dummyResourceCtl.getAttributePath(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_QUOTE_NAME), "Arr!"); } + /** + * MID-3079 + */ + @Test + public void test220PreviewJackAssignRolePirate() throws Exception { + final String TEST_NAME = "test220PreviewJackAssignRolePirate"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestPreviewChanges.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + ObjectDelta delta = createAssignmentFocusDelta(UserType.class, USER_JACK_OID, + ROLE_PIRATE_OID, RoleType.COMPLEX_TYPE, null, null, null, true); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + ModelContext modelContext = modelInteractionService.previewChanges(MiscSchemaUtil.createCollection(delta), + null, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + display("Preview context", modelContext); + assertNotNull("Null model context", modelContext); + + result.computeStatus(); + TestUtil.assertSuccess(result); + + ModelElementContext focusContext = modelContext.getFocusContext(); + assertNotNull("Model focus context missing", focusContext); + + Collection projectionContexts = modelContext.getProjectionContexts(); + assertNotNull("Null model projection context list", projectionContexts); + assertEquals("Unexpected number of projection contexts", 1, projectionContexts.size()); + ModelProjectionContext accContext = projectionContexts.iterator().next(); + assertNotNull("Null model projection context", accContext); + + ObjectDelta accountPrimaryDelta = accContext.getPrimaryDelta(); + assertNull("Unexpected account primary delta", accountPrimaryDelta); + + ObjectDelta accountSecondaryDelta = accContext.getSecondaryDelta(); + assertEquals(ChangeType.MODIFY, accountSecondaryDelta.getChangeType()); + + assertAccountItemModify(accountSecondaryDelta, + SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS, + null, // old + null, // add + null, // delete + new ActivationStatusType[] { ActivationStatusType.ENABLED }); // replace + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_WEAPON_NAME, + null, // old + new String[] { ROLE_PIRATE_WEAPON }, // add + null, // delete + null); // replace + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME, + null, // old + new String[] { ROLE_PIRATE_TITLE }, // add + null, // delete + null); // replace + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DUMMY_ACCOUNT_ATTRIBUTE_SEA_NAME, + null, // old + null, // add + null, // delete + new String[] { "jack sailed The Seven Seas, immediately , role , with this The Seven Seas while focused on (in Pirate)" }); // replace + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_GOSSIP_NAME, + null, // old + new String[] { "Jack Sparrow is the best pirate Caribbean has ever seen" }, // add + null, // delete + null); // replace + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_QUOTE_NAME, + null, // old + new String[] { RESOURCE_DUMMY_QUOTE }, // add + null, // delete + null); // replace + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_DRINK_NAME, + null, // old + new String[] { RESOURCE_DUMMY_DRINK }, // add + null, // delete + null); // replace + + PrismAsserts.assertModifications(accountSecondaryDelta, 14); + } + + /** + * Make sure that Guybrush has an existing account and that it is properly populated. + * We will use this setup in following tests. + */ + @Test + public void test230GuybrushAssignAccountDummy() throws Exception { + final String TEST_NAME = "test230GuybrushAssignAccountDummy"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestPreviewChanges.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + ObjectDelta delta = createAssignmentFocusDelta(UserType.class, USER_GUYBRUSH_OID, + ROLE_PIRATE_OID, RoleType.COMPLEX_TYPE, null, null, null, true); + + ModelExecuteOptions options = ModelExecuteOptions.createReconcile(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + modifyUserReplace(USER_GUYBRUSH_OID, new ItemPath(UserType.F_EXTENSION, PIRACY_WEAPON), task, result, + "tongue"); + assignAccount(USER_GUYBRUSH_OID, RESOURCE_DUMMY_OID, null, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + DummyAccount dummyAccount = assertDummyAccount(null, USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME, true); + display("Dummy account after", dummyAccount); + dummyAccount.addAttributeValue(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME, "Great Pirate"); + } + + /** + * MID-3079 + */ + @Test + public void test232PreviewGuybrushAddRolePirate() throws Exception { + final String TEST_NAME = "test232PreviewGuybrushAddRolePirate"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestPreviewChanges.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + ObjectDelta delta = createAssignmentFocusDelta(UserType.class, USER_GUYBRUSH_OID, + ROLE_PIRATE_OID, RoleType.COMPLEX_TYPE, null, null, null, true); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + ModelContext modelContext = modelInteractionService.previewChanges(MiscSchemaUtil.createCollection(delta), + null, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + display("Preview context", modelContext); + assertNotNull("Null model context", modelContext); + + result.computeStatus(); + TestUtil.assertSuccess(result); + + ModelElementContext focusContext = modelContext.getFocusContext(); + assertNotNull("Model focus context missing", focusContext); + + Collection projectionContexts = modelContext.getProjectionContexts(); + assertNotNull("Null model projection context list", projectionContexts); + assertEquals("Unexpected number of projection contexts", 1, projectionContexts.size()); + ModelProjectionContext accContext = projectionContexts.iterator().next(); + assertNotNull("Null model projection context", accContext); + + ObjectDelta accountPrimaryDelta = accContext.getPrimaryDelta(); + assertNull("Unexpected account primary delta", accountPrimaryDelta); + + ObjectDelta accountSecondaryDelta = accContext.getSecondaryDelta(); + assertEquals(ChangeType.MODIFY, accountSecondaryDelta.getChangeType()); + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME, + new String[] { "Great Pirate" }, // old + new String[] { ROLE_PIRATE_TITLE }, // add + null, // delete + null); // replace + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DUMMY_ACCOUNT_ATTRIBUTE_SEA_NAME, + null, // old + null, // add + null, // delete + new String[] { "guybrush sailed The Seven Seas, immediately , role , with this The Seven Seas while focused on (in Pirate)" }); // replace + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_GOSSIP_NAME, + null, // old + new String[] { "Guybrush Threepwood is the best pirate Melee Island has ever seen" }, // add + null, // delete + null); // replace + + PrismAsserts.assertModifications(accountSecondaryDelta, 3); + } + + /** + * MID-3079 + */ + @Test + public void test234PreviewGuybrushAddRolePirateRecon() throws Exception { + final String TEST_NAME = "test234PreviewGuybrushAddRolePirateRecon"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestPreviewChanges.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + ObjectDelta delta = createAssignmentFocusDelta(UserType.class, USER_GUYBRUSH_OID, + ROLE_PIRATE_OID, RoleType.COMPLEX_TYPE, null, null, null, true); + + ModelExecuteOptions options = ModelExecuteOptions.createReconcile(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + ModelContext modelContext = modelInteractionService.previewChanges(MiscSchemaUtil.createCollection(delta), + options, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + display("Preview context", modelContext); + assertNotNull("Null model context", modelContext); + + result.computeStatus(); + TestUtil.assertSuccess(result); + + ModelElementContext focusContext = modelContext.getFocusContext(); + assertNotNull("Model focus context missing", focusContext); + + Collection projectionContexts = modelContext.getProjectionContexts(); + assertNotNull("Null model projection context list", projectionContexts); + assertEquals("Unexpected number of projection contexts", 1, projectionContexts.size()); + ModelProjectionContext accContext = projectionContexts.iterator().next(); + assertNotNull("Null model projection context", accContext); + + ObjectDelta accountPrimaryDelta = accContext.getPrimaryDelta(); + assertNull("Unexpected account primary delta", accountPrimaryDelta); + + ObjectDelta accountSecondaryDelta = accContext.getSecondaryDelta(); + assertEquals(ChangeType.MODIFY, accountSecondaryDelta.getChangeType()); + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME, + new String[] { "Great Pirate" }, // old + new String[] { ROLE_PIRATE_TITLE }, // add + null, // delete + null); // replace + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DUMMY_ACCOUNT_ATTRIBUTE_SEA_NAME, + null, // old + null, // add + null, // delete + new String[] { "guybrush sailed The Seven Seas, immediately , role , with this The Seven Seas while focused on (in Pirate)" }); // replace + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_GOSSIP_NAME, + null, // old + new String[] { "Guybrush Threepwood is the best pirate Melee Island has ever seen" }, // add + null, // delete + null); // replace + + PrismAsserts.assertModifications(accountSecondaryDelta, 3); + } + + /** + * MID-3079 + */ + @Test + public void test236PreviewGuybrushAddRoleSailor() throws Exception { + final String TEST_NAME = "test236PreviewGuybrushAddRoleSailor"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestPreviewChanges.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + ObjectDelta delta = createAssignmentFocusDelta(UserType.class, USER_GUYBRUSH_OID, + ROLE_SAILOR_OID, RoleType.COMPLEX_TYPE, null, null, null, true); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + ModelContext modelContext = modelInteractionService.previewChanges(MiscSchemaUtil.createCollection(delta), + null, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + display("Preview context", modelContext); + assertNotNull("Null model context", modelContext); + + result.computeStatus(); + TestUtil.assertSuccess(result); + + ModelElementContext focusContext = modelContext.getFocusContext(); + assertNotNull("Model focus context missing", focusContext); + + Collection projectionContexts = modelContext.getProjectionContexts(); + assertNotNull("Null model projection context list", projectionContexts); + assertEquals("Unexpected number of projection contexts", 1, projectionContexts.size()); + ModelProjectionContext accContext = projectionContexts.iterator().next(); + assertNotNull("Null model projection context", accContext); + + ObjectDelta accountPrimaryDelta = accContext.getPrimaryDelta(); + assertNull("Unexpected account primary delta", accountPrimaryDelta); + + ObjectDelta accountSecondaryDelta = accContext.getSecondaryDelta(); + assertEquals(ChangeType.MODIFY, accountSecondaryDelta.getChangeType()); + + assertAccountDefaultDummyAttributeModify(accountSecondaryDelta, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_DRINK_NAME, + new String[] { RESOURCE_DUMMY_DRINK }, // old + new String[] { ROLE_SAILOR_DRINK }, // add + null, // delete + null); // replace + + PrismAsserts.assertModifications(accountSecondaryDelta, 1); + } + + @Test + public void test239GuybrushUnAssignAccountDummy() throws Exception { + final String TEST_NAME = "test239GuybrushUnAssignAccountDummy"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestPreviewChanges.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + unassignAccount(USER_GUYBRUSH_OID, RESOURCE_DUMMY_OID, null, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertNoDummyAccount(null, USER_GUYBRUSH_USERNAME); + } + + /** + * Make sure that Guybrush has an existing account and that it is properly populated. + * We will use this setup in following tests. + */ + @Test + public void test240GuybrushAssignAccountDummyRelative() throws Exception { + final String TEST_NAME = "test240GuybrushAssignAccountDummyRelative"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestPreviewChanges.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + assignAccount(USER_GUYBRUSH_OID, RESOURCE_DUMMY_RELATIVE_OID, null, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + DummyAccount dummyAccount = assertDummyAccount(RESOURCE_DUMMY_RELATIVE_NAME, USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME, true); + display("Dummy account after", dummyAccount); + dummyAccount.addAttributeValue(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME, "Great Pirate"); + } + + /** + * MID-3079 + * Relative operation on a relative resource. The account is not retrieved. + * There are no old values at all. + */ + @Test + public void test242PreviewGuybrushAddRolePirateRelative() throws Exception { + final String TEST_NAME = "test242PreviewGuybrushAddRolePirateRelative"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestPreviewChanges.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + ObjectDelta delta = createAssignmentFocusDelta(UserType.class, USER_GUYBRUSH_OID, + ROLE_PIRATE_RELATIVE_OID, RoleType.COMPLEX_TYPE, null, null, null, true); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + ModelContext modelContext = modelInteractionService.previewChanges(MiscSchemaUtil.createCollection(delta), + null, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + display("Preview context", modelContext); + assertNotNull("Null model context", modelContext); + + result.computeStatus(); + TestUtil.assertSuccess(result); + + ModelElementContext focusContext = modelContext.getFocusContext(); + assertNotNull("Model focus context missing", focusContext); + + Collection projectionContexts = modelContext.getProjectionContexts(); + assertNotNull("Null model projection context list", projectionContexts); + assertEquals("Unexpected number of projection contexts", 1, projectionContexts.size()); + ModelProjectionContext accContext = projectionContexts.iterator().next(); + assertNotNull("Null model projection context", accContext); + + ObjectDelta accountPrimaryDelta = accContext.getPrimaryDelta(); + assertNull("Unexpected account primary delta", accountPrimaryDelta); + + ObjectDelta accountSecondaryDelta = accContext.getSecondaryDelta(); + assertEquals(ChangeType.MODIFY, accountSecondaryDelta.getChangeType()); + + assertAccountDummyAttributeModify(accountSecondaryDelta, + RESOURCE_DUMMY_RELATIVE_NAME, DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_WEAPON_NAME, + null, // old + new String[] { ROLE_PIRATE_WEAPON }, // add + null, // delete + null); // replace + + assertAccountDummyAttributeModify(accountSecondaryDelta, + RESOURCE_DUMMY_RELATIVE_NAME, DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME, + null, // old + new String[] { ROLE_PIRATE_TITLE }, // add + null, // delete + null); // replace + + assertAccountDummyAttributeModify(accountSecondaryDelta, + RESOURCE_DUMMY_RELATIVE_NAME, DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_GOSSIP_NAME, + null, // old + new String[] { "Guybrush Threepwood is the best pirate Melee Island has ever seen" }, // add + null, // delete + null); // replace + + PrismAsserts.assertModifications(accountSecondaryDelta, 3); + } + + /** + * MID-3079 + */ + @Test + public void test244PreviewGuybrushAddRolePirateRelativeRecon() throws Exception { + final String TEST_NAME = "test244PreviewGuybrushAddRolePirateRelativeRecon"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestPreviewChanges.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + ObjectDelta delta = createAssignmentFocusDelta(UserType.class, USER_GUYBRUSH_OID, + ROLE_PIRATE_RELATIVE_OID, RoleType.COMPLEX_TYPE, null, null, null, true); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + ModelContext modelContext = modelInteractionService.previewChanges(MiscSchemaUtil.createCollection(delta), + ModelExecuteOptions.createReconcile(), task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + display("Preview context", modelContext); + assertNotNull("Null model context", modelContext); + + result.computeStatus(); + TestUtil.assertSuccess(result); + + ModelElementContext focusContext = modelContext.getFocusContext(); + assertNotNull("Model focus context missing", focusContext); + + Collection projectionContexts = modelContext.getProjectionContexts(); + assertNotNull("Null model projection context list", projectionContexts); + assertEquals("Unexpected number of projection contexts", 1, projectionContexts.size()); + ModelProjectionContext accContext = projectionContexts.iterator().next(); + assertNotNull("Null model projection context", accContext); + + ObjectDelta accountPrimaryDelta = accContext.getPrimaryDelta(); + assertNull("Unexpected account primary delta", accountPrimaryDelta); + + ObjectDelta accountSecondaryDelta = accContext.getSecondaryDelta(); + assertEquals(ChangeType.MODIFY, accountSecondaryDelta.getChangeType()); + + assertAccountDummyAttributeModify(accountSecondaryDelta, + RESOURCE_DUMMY_RELATIVE_NAME, DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_WEAPON_NAME, + new String[] { "tongue" }, // old + new String[] { ROLE_PIRATE_WEAPON }, // add + null, // delete + null); // replace + + assertAccountDummyAttributeModify(accountSecondaryDelta, + RESOURCE_DUMMY_RELATIVE_NAME, DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME, + new String[] { "Great Pirate" }, // old + new String[] { ROLE_PIRATE_TITLE }, // add + null, // delete + null); // replace + + assertAccountDummyAttributeModify(accountSecondaryDelta, + RESOURCE_DUMMY_RELATIVE_NAME, DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_GOSSIP_NAME, + null, // old + new String[] { "Guybrush Threepwood is the best pirate Melee Island has ever seen" }, // add + null, // delete + null); // replace + + PrismAsserts.assertModifications(accountSecondaryDelta, 3); + } + + @Test + public void test249GuybrushUnAssignAccountDummyRelative() throws Exception { + final String TEST_NAME = "test249GuybrushUnAssignAccountDummyRelative"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestPreviewChanges.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + unassignAccount(USER_GUYBRUSH_OID, RESOURCE_DUMMY_RELATIVE_OID, null, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertNoDummyAccount(RESOURCE_DUMMY_RELATIVE_NAME, USER_GUYBRUSH_USERNAME); + } + + + private void assertAccountDefaultDummyAttributeModify(ObjectDelta accountDelta, + String attrName, + T[] expectedOldValues, T[] expectedAddValues, T[] expectedDeleteValues, T[] expectedReplaceValues) { + ItemPath itemPath = getDummyResourceController().getAttributePath(attrName); + assertAccountItemModify(accountDelta, itemPath, expectedOldValues, expectedAddValues, expectedDeleteValues, expectedReplaceValues); + } + + private void assertAccountDummyAttributeModify(ObjectDelta accountDelta, + String dummyName, String attrName, + T[] expectedOldValues, T[] expectedAddValues, T[] expectedDeleteValues, T[] expectedReplaceValues) { + ItemPath itemPath = getDummyResourceController(dummyName).getAttributePath(attrName); + assertAccountItemModify(accountDelta, itemPath, expectedOldValues, expectedAddValues, expectedDeleteValues, expectedReplaceValues); + } + + private void assertAccountItemModify(ObjectDelta accountDelta, + ItemPath itemPath, + T[] expectedOldValues, T[] expectedAddValues, T[] expectedDeleteValues, T[] expectedReplaceValues) { + PropertyDelta attrDelta = accountDelta.findPropertyDelta(itemPath); + assertNotNull("No delta for "+itemPath+" in "+accountDelta, attrDelta); + PrismAsserts.assertPropertyDelta(attrDelta, expectedOldValues, expectedAddValues, expectedDeleteValues, expectedReplaceValues); + } + // MAPPING TESTS // following tests mostly check correct functions of mappings @@ -988,9 +1553,12 @@ public void test600ModifyElaineUserDummyReplace() throws Exception { display("Input deltas: ", deltas); // WHEN + TestUtil.displayWhen(TEST_NAME); ModelContext modelContext = modelInteractionService.previewChanges(deltas, new ModelExecuteOptions(), task, result); // THEN + TestUtil.displayThen(TEST_NAME); + display("Preview context", modelContext); assertNotNull("Null model context", modelContext); @@ -1097,9 +1665,12 @@ ACCOUNT_SHADOW_ELAINE_DUMMY_OID, getDummyResourceObject(), display("Input deltas: ", deltas); // WHEN + TestUtil.displayWhen(TEST_NAME); ModelContext modelContext = modelInteractionService.previewChanges(deltas, new ModelExecuteOptions(), task, result); // THEN + TestUtil.displayThen(TEST_NAME); + display("Preview context", modelContext); assertNotNull("Null model context", modelContext); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestSecurity.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestSecurity.java index 7d496e1212a..befd02230bd 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestSecurity.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestSecurity.java @@ -54,10 +54,12 @@ import com.evolveum.midpoint.schema.util.ObjectQueryUtil; import com.evolveum.midpoint.security.api.Authorization; import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.security.api.ItemSecurityDecisions; 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.Producer; +import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; @@ -84,8 +86,11 @@ 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.Map.Entry; +import java.util.Set; import static com.evolveum.midpoint.test.IntegrationTestTools.display; import static org.testng.AssertJUnit.assertEquals; @@ -2102,6 +2107,9 @@ public void run(Task task, OperationResult result) throws Exception { assertRoleTypes(spec, "application", "nonexistent"); assertFilter(spec.getFilter(), TypeFilter.class); + assertAllowRequestItems(USER_JACK_OID, ROLE_APPLICATION_1_OID, null, + AssignmentType.F_TARGET_REF, ActivationType.F_VALID_FROM, ActivationType.F_VALID_TO); + assertGlobalStateUntouched(); } @@ -2155,6 +2163,8 @@ public void run(Task task, OperationResult result) throws Exception { assertRoleTypes(spec); assertFilter(spec.getFilter(), TypeFilter.class); + assertAllowRequestItems(USER_JACK_OID, ROLE_APPLICATION_1_OID, AuthorizationDecisionType.ALLOW); + assertGlobalStateUntouched(); } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestUserTemplate.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestUserTemplate.java index 245935b54b6..20fae42924c 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestUserTemplate.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestUserTemplate.java @@ -108,7 +108,7 @@ public class TestUserTemplate extends AbstractInitializedModelIntegrationTest { private static final String EMPLOYEE_TYPE_MAROONED = "marooned"; - private static final int NUMBER_OF_ROLES = 19; + private static final int NUMBER_OF_ROLES = 20; private static String jackEmployeeNumber; diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/scripting/TestScriptingBasic.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/scripting/TestScriptingBasic.java index 308f0e961ce..87e6e1f4f8d 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/scripting/TestScriptingBasic.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/scripting/TestScriptingBasic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Evolveum + * Copyright (c) 2010-2017 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -197,7 +197,7 @@ public void test205SearchForResources() throws Exception { IntegrationTestTools.display("output", output.getData()); result.computeStatus(); TestUtil.assertSuccess(result); - assertEquals(12, output.getData().size()); + assertEquals(13, output.getData().size()); } @Test diff --git a/model/model-intest/src/test/resources/common/resource-dummy-relative.xml b/model/model-intest/src/test/resources/common/resource-dummy-relative.xml new file mode 100644 index 00000000000..8ce27000990 --- /dev/null +++ b/model/model-intest/src/test/resources/common/resource-dummy-relative.xml @@ -0,0 +1,241 @@ + + + + + + + + Dummy Resource Relative + + + + + connectorType + com.evolveum.icf.dummy.connector.DummyConnector + + + connectorVersion + 2.0 + + + + + + + + relative + + + + false + false + false + + + + + + + account + default + true + ri:AccountObjectClass + + icfs:name + + + $user/name + + + + + + + + icfs:uid + UID + + + ri:fullname + + + $user/fullName + + + + + ri:title + + + ri:location + + + + $user/locality + + + + + + ri:ship + + + ri:loot + + + ri:weapon + + + + declare namespace piracy = "http://midpoint.evolveum.com/xml/ns/samples/piracy"; + $user/extension/piracy:weapon + + + + + + ri:drink + false + + + rum + + + + + ri:quote + true + + + Arr! + + + + + ri:gossip + Gossip + true + + + ri:water + + true + + + + + fishy + + + + + + ri:group + false + entitlement + group + objectToSubject + ri:members + icfs:name + + + + ri:priv + entitlement + privilege + subjectToObject + ri:privileges + icfs:name + + + + 5 + + + + + + + + + + + + + + + + + + + + + + entitlement + group + true + ri:GroupObjectClass + + icfs:name + + + $focus/name + + + declare namespace t="http://prism.evolveum.com/xml/ns/public/types-3"; + t:norm + + + + + ri:description + + + $focus/description + + + + + ri:members + minimal + + + + + entitlement + privilege + false + ri:CustomprivilegeObjectClass + + + + + diff --git a/model/model-intest/src/test/resources/common/role-pirate-relative.xml b/model/model-intest/src/test/resources/common/role-pirate-relative.xml new file mode 100644 index 00000000000..4768381a196 --- /dev/null +++ b/model/model-intest/src/test/resources/common/role-pirate-relative.xml @@ -0,0 +1,82 @@ + + + Relative Pirate + + + + account + + ri:title + + + Bloody Pirate + + + + + ri:location + + + locality + + + + + + + + ri:weapon + + + cutlass + + + + + ri:gossip + + + $user/fullName + + + $user/locality + + + + + + + + + + http://midpoint.evolveum.com/xml/ns/test/authorization#loot + execution + + diff --git a/model/model-intest/src/test/resources/security/role-assign-application-roles.xml b/model/model-intest/src/test/resources/security/role-assign-application-roles.xml index c5de6f6847d..ecf2c01a663 100644 --- a/model/model-intest/src/test/resources/security/role-assign-application-roles.xml +++ b/model/model-intest/src/test/resources/security/role-assign-application-roles.xml @@ -23,7 +23,6 @@ http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#assign - http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#unassign request RoleType @@ -48,6 +47,24 @@ + assignment/targetRef + assignment/activation/validFrom + assignment/activation/validTo + + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#unassign + request + + RoleType + + + + roleType + application + + + + http://midpoint.evolveum.com/xml/ns/public/security/authorization-model-3#add 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 b17224c95f1..c8b6dd80e92 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 @@ -71,6 +71,7 @@ import com.evolveum.midpoint.schema.util.*; import com.evolveum.midpoint.security.api.Authorization; import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.security.api.ItemSecurityDecisions; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.security.api.SecurityEnforcer; import com.evolveum.midpoint.security.api.UserProfileService; @@ -98,6 +99,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.AdminGuiConfigurationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentSelectorType; 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.AuthorizationPhaseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConstructionType; @@ -3771,6 +3773,42 @@ protected void assertRoleTypes(RoleSelectionSpecification roleSpec, String... ex } } } + + protected void assertAllowRequestItems(String userOid, String targetRoleOid, AuthorizationDecisionType expectedDefaultDecision, QName... expectedAllowedItemQNames) throws SchemaException, SecurityViolationException, CommunicationException, ObjectNotFoundException, ConfigurationException { + PrismObject user = getUser(userOid); + PrismObject target = getRole(targetRoleOid); + + ItemSecurityDecisions decisions = modelInteractionService.getAllowedRequestAssignmentItems(user, target); + display("Request decisions for "+target, decisions); + assertEquals("Wrong assign default decision", expectedDefaultDecision, decisions.getDefaultDecision()); + assertEquals("Unexpected number of allowed items", expectedAllowedItemQNames.length, decisions.getItemDecisionMap().size()); + + decisions.getItemDecisionMap().forEach( + (path,decision) -> { + assertEquals("wrong item "+path+" decision", AuthorizationDecisionType.ALLOW, decision); + QName lastPathName = path.lastNamed().getName(); + if (!Arrays.stream(expectedAllowedItemQNames).anyMatch(qname -> QNameUtil.match(qname, lastPathName) )) { + AssertJUnit.fail("Unexpected path "+path); + } + } + ); + } + + + protected void assertEncryptedUserPassword(String userOid, String expectedClearPassword) throws EncryptionException, ObjectNotFoundException, SchemaException { + OperationResult result = new OperationResult(AbstractIntegrationTest.class.getName()+".assertEncryptedUserPassword"); + PrismObject user = repositoryService.getObject(UserType.class, userOid, null, result); + result.computeStatus(); + TestUtil.assertSuccess(result); + assertEncryptedUserPassword(user, expectedClearPassword); + } + + protected void assertEncryptedUserPassword(PrismObject user, String expectedClearPassword) throws EncryptionException { + UserType userType = user.asObjectable(); + ProtectedStringType protectedActualPassword = userType.getCredentials().getPassword().getValue(); + String actualClearPassword = protector.decryptString(protectedActualPassword); + assertEquals("Wrong password for "+user, expectedClearPassword, actualClearPassword); + } protected void assertPasswordMetadata(PrismObject user, boolean create, XMLGregorianCalendar start, XMLGregorianCalendar end, String actorOid, String channel) { PrismContainer metadataContainer = user.findContainer(new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_PASSWORD, PasswordType.F_METADATA)); diff --git a/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/ItemSecurityDecisions.java b/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/ItemSecurityDecisions.java new file mode 100644 index 00000000000..6ee2919a110 --- /dev/null +++ b/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/ItemSecurityDecisions.java @@ -0,0 +1,63 @@ +/** + * 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.security.api; + +import java.util.HashMap; +import java.util.Map; + +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.util.DebugDumpable; +import com.evolveum.midpoint.util.DebugUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationDecisionType; + +/** + * @author semancik + * + */ +public class ItemSecurityDecisions implements DebugDumpable { + + private AuthorizationDecisionType defaultDecision = null; + private Map itemDecisionMap = new HashMap<>(); + + public AuthorizationDecisionType getDefaultDecision() { + return defaultDecision; + } + + public void setDefaultDecision(AuthorizationDecisionType defaultDecision) { + this.defaultDecision = defaultDecision; + } + + public Map getItemDecisionMap() { + return itemDecisionMap; + } + + @Override + public String debugDump(int indent) { + StringBuilder sb = new StringBuilder(); + DebugUtil.debugDumpLabelLn(sb, "ItemSecurityDecisions", indent); + DebugUtil.debugDumpWithLabelToStringLn(sb, "defaultDecision", defaultDecision, indent + 1); + DebugUtil.debugDumpLabelLn(sb, "itemDecisionMap", indent + 1); + DebugUtil.debugDumpMapMultiLine(sb, itemDecisionMap, indent + 2); + return sb.toString(); + } + + @Override + public String toString() { + return "ItemSecurityDecisions(defaultDecision=" + defaultDecision + ", itemDecisionMap=" + itemDecisionMap + + ")"; + } + +} diff --git a/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/SecurityEnforcer.java b/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/SecurityEnforcer.java index d9138497ce7..2ffc88ed02a 100644 --- a/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/SecurityEnforcer.java +++ b/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/SecurityEnforcer.java @@ -24,6 +24,7 @@ import com.evolveum.midpoint.util.Producer; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationPhaseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; @@ -95,4 +96,9 @@ ObjectFilter preProcessObjectFilter T runPrivileged(Producer producer); + /** + * Returns decisions for individual items for "assign" authorization. This is usually applicable to assignment parameters. + */ + ItemSecurityDecisions getAllowedRequestAssignmentItems( MidPointPrincipal midPointPrincipal, PrismObject object, PrismObject target, OwnerResolver ownerResolver) throws SchemaException; + } 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 a559d75797f..8c14fa20cc1 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 @@ -64,6 +64,68 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import com.evolveum.midpoint.prism.Containerable; +import com.evolveum.midpoint.prism.Item; +import com.evolveum.midpoint.prism.PrismContainer; +import com.evolveum.midpoint.prism.PrismContainerValue; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.PrismObjectDefinition; +import com.evolveum.midpoint.prism.PrismReferenceDefinition; +import com.evolveum.midpoint.prism.Visitable; +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; +import com.evolveum.midpoint.prism.match.MatchingRuleRegistry; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.AllFilter; +import com.evolveum.midpoint.prism.query.InOidFilter; +import com.evolveum.midpoint.prism.query.NoneFilter; +import com.evolveum.midpoint.prism.query.NotFilter; +import com.evolveum.midpoint.prism.query.ObjectFilter; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.query.OrgFilter; +import com.evolveum.midpoint.prism.query.QueryJaxbConvertor; +import com.evolveum.midpoint.prism.query.RefFilter; +import com.evolveum.midpoint.prism.query.TypeFilter; +import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.MiscSchemaUtil; +import com.evolveum.midpoint.schema.util.ObjectQueryUtil; +import com.evolveum.midpoint.security.api.Authorization; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.security.api.ItemSecurityDecisions; +import com.evolveum.midpoint.security.api.MidPointPrincipal; +import com.evolveum.midpoint.security.api.ObjectSecurityConstraints; +import com.evolveum.midpoint.security.api.OwnerResolver; +import com.evolveum.midpoint.security.api.SecurityEnforcer; +import com.evolveum.midpoint.security.api.SecurityUtil; +import com.evolveum.midpoint.security.api.UserProfileService; +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; +import com.evolveum.midpoint.util.exception.SystemException; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationDecisionType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationPhaseType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.SubjectedObjectSelectorType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgRelationObjectSpecificationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgScopeType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OwnedObjectSelectorType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.SpecialObjectSpecificationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; +import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; /** * @author Radovan Semancik @@ -262,12 +324,31 @@ private boolean isAuthorizedInterna return allow; } - private boolean processAuthorizationObject(PrismObject object, final Collection allowedItems) { + private boolean processAuthorizationObject(PrismContainer object, final Collection allowedItems) { + final MutableBoolean itemDecision = new MutableBoolean(true); + object.accept(createItemVisitor(allowedItems, itemDecision)); + return itemDecision.booleanValue(); + } + + private boolean processAuthorizationContainerDelta(ContainerDelta cval, final Collection allowedItems) { final MutableBoolean itemDecision = new MutableBoolean(true); - Visitor visitor = new Visitor() { + cval.accept(createItemVisitor(allowedItems, itemDecision)); + return itemDecision.booleanValue(); + } + + private Visitor createItemVisitor(final Collection allowedItems, final MutableBoolean itemDecision) { + return new Visitor() { @Override public void visit(Visitable visitable) { if (visitable instanceof Item) { + + // TODO: problem with empty containers such as + // orderConstraint in assignment. Skip all + // empty items ... for now. + if (((Item)visitable).isEmpty()) { + return; + } + ItemPath itemPath = ((Item)visitable).getPath(); if (itemPath != null && !itemPath.isEmpty()) { if (!isInList(itemPath, allowedItems)) { @@ -278,8 +359,6 @@ public void visit(Visitable visitable) { } } }; - object.accept(visitor); - return itemDecision.booleanValue(); } private boolean processAuthorizationDelta(ObjectDelta delta, final Collection allowedItems) { @@ -288,9 +367,17 @@ private boolean processAuthorizationDelta(ObjectDelta } else { for (ItemDelta itemDelta: delta.getModifications()) { ItemPath itemPath = itemDelta.getPath(); - if (!isInList(itemPath, allowedItems)) { - LOGGER.trace(" DENY operation because item {} in the delta is not allowed", itemPath); - return false; + if (itemDelta instanceof ContainerDelta) { + if (!isInList(itemPath, allowedItems)) { + if (!processAuthorizationContainerDelta((ContainerDelta)itemDelta, allowedItems)) { + return false; + } + } + } else { + if (!isInList(itemPath, allowedItems)) { + LOGGER.trace(" DENY operation because item {} in the delta is not allowed", itemPath); + return false; + } } } return true; @@ -477,7 +564,7 @@ private boolean hasParentOrgRef(PrismObject object, St } private boolean isApplicableItem(Authorization autz, - PrismObject object, ObjectDelta delta) { + PrismObject object, ObjectDelta delta) throws SchemaException { List itemPaths = autz.getItem(); if (itemPaths == null || itemPaths.isEmpty()) { // No item constraints. Applicable for all items. @@ -488,8 +575,7 @@ private boolean isApplicableItem(Au ItemPath itemPath = itemPathType.getItemPath(); if (delta == null) { if (object != null) { - Item item = object.findItem(itemPath); - if (item != null && !item.isEmpty()) { + if (object.containsItem(itemPath, false)) { LOGGER.trace(" applicable object item "+itemPath); return true; } @@ -654,51 +740,46 @@ public ObjectSecurityConstraints compileSecurityConstrain ObjectSecurityConstraintsImpl objectSecurityConstraints = new ObjectSecurityConstraintsImpl(); Collection authorities = getAuthorities(principal); if (authorities != null) { - for (GrantedAuthority authority: authorities) { - if (authority instanceof Authorization) { - Authorization autz = (Authorization)authority; - String autzHumanReadableDesc = autz.getHumanReadableDesc(); - LOGGER.trace("Evaluating {}", autzHumanReadableDesc); - - // skip action applicability evaluation. We are interested in all actions - - // object - if (isApplicable(autz.getObject(), object, principal, ownerResolver, "object", autzHumanReadableDesc)) { - LOGGER.trace(" {} applicable for object {} (continuing evaluation)", autzHumanReadableDesc, object); + for (Authorization autz: authorities) { + String autzHumanReadableDesc = autz.getHumanReadableDesc(); + LOGGER.trace("Evaluating {}", autzHumanReadableDesc); + + // skip action applicability evaluation. We are interested in all actions + + // object + if (isApplicable(autz.getObject(), object, principal, ownerResolver, "object", autzHumanReadableDesc)) { + LOGGER.trace(" {} applicable for object {} (continuing evaluation)", autzHumanReadableDesc, object); + } else { + LOGGER.trace(" {} not applicable for object {}, none of the object specifications match (breaking evaluation)", + autzHumanReadableDesc, object); + continue; + } + + // skip target applicability evaluation. We do not have a target here + + List actions = autz.getAction(); + AuthorizationPhaseType phase = autz.getPhase(); + AuthorizationDecisionType decision = autz.getDecision(); + if (decision == null || decision == AuthorizationDecisionType.ALLOW) { + Collection items = getItems(autz); + if (items == null || items.isEmpty()) { + applyDecision(objectSecurityConstraints.getActionDecisionMap(), actions, phase, AuthorizationDecisionType.ALLOW); } else { - LOGGER.trace(" {} not applicable for object {}, none of the object specifications match (breaking evaluation)", - autzHumanReadableDesc, object); - continue; - } - - // skip target applicability evaluation. We do not have a target here - - List actions = autz.getAction(); - AuthorizationPhaseType phase = autz.getPhase(); - AuthorizationDecisionType decision = autz.getDecision(); - if (decision == null || decision == AuthorizationDecisionType.ALLOW) { - Collection items = getItems(autz); - if (items == null || items.isEmpty()) { - applyDecision(objectSecurityConstraints.getActionDecisionMap(), actions, phase, AuthorizationDecisionType.ALLOW); - } else { - for (ItemPath item: items) { - applyItemDecision(objectSecurityConstraints.getItemConstraintMap(), item, actions, phase, AuthorizationDecisionType.ALLOW); - } + for (ItemPath item: items) { + applyItemDecision(objectSecurityConstraints.getItemConstraintMap(), item, actions, phase, AuthorizationDecisionType.ALLOW); } + } + } else { + Collection items = getItems(autz); + if (items == null || items.isEmpty()) { + applyDecision(objectSecurityConstraints.getActionDecisionMap(), actions, phase, AuthorizationDecisionType.DENY); } else { - Collection items = getItems(autz); - if (items == null || items.isEmpty()) { - applyDecision(objectSecurityConstraints.getActionDecisionMap(), actions, phase, AuthorizationDecisionType.DENY); - } else { - for (ItemPath item: items) { - applyItemDecision(objectSecurityConstraints.getItemConstraintMap(), item, actions, phase, AuthorizationDecisionType.DENY); - } + for (ItemPath item: items) { + applyItemDecision(objectSecurityConstraints.getItemConstraintMap(), item, actions, phase, AuthorizationDecisionType.DENY); } } - - } else { - LOGGER.warn("Unknown authority type {} in user {}", authority.getClass(), getUsername(principal)); } + } } @@ -1057,8 +1138,88 @@ private Object getUsername(MidPointPrincipal principal) { return principal==null?null:principal.getUsername(); } + @Override + public ItemSecurityDecisions getAllowedRequestAssignmentItems( MidPointPrincipal midPointPrincipal, PrismObject object, PrismObject target, OwnerResolver ownerResolver) throws SchemaException { + + ItemSecurityDecisions decisions = new ItemSecurityDecisions(); + + for(Authorization autz: getAuthorities(midPointPrincipal)) { + String autzHumanReadableDesc = autz.getHumanReadableDesc(); + LOGGER.trace("Evaluating {}", autzHumanReadableDesc); + + // First check if the authorization is applicable. + + // action + if (!autz.getAction().contains(AuthorizationConstants.AUTZ_UI_ASSIGN_ACTION_URL) && !autz.getAction().contains(AuthorizationConstants.AUTZ_ALL_URL)) { + LOGGER.trace(" {} not applicable for operation {}", autzHumanReadableDesc, AuthorizationConstants.AUTZ_UI_ASSIGN_ACTION_URL); + continue; + } + + // phase + if (autz.getPhase() != null && autz.getPhase() != AuthorizationPhaseType.REQUEST) { + LOGGER.trace(" {} is not applicable for phase {} (breaking evaluation)", autzHumanReadableDesc, AuthorizationPhaseType.REQUEST); + continue; + } + + // object + if (isApplicable(autz.getObject(), object, midPointPrincipal, ownerResolver, "object", autzHumanReadableDesc)) { + LOGGER.trace(" {} applicable for object {} (continuing evaluation)", autzHumanReadableDesc, object); + } else { + LOGGER.trace(" {} not applicable for object {}, none of the object specifications match (breaking evaluation)", + autzHumanReadableDesc, object); + continue; + } + + // target + if (isApplicable(autz.getTarget(), target, midPointPrincipal, ownerResolver, "target", autzHumanReadableDesc)) { + LOGGER.trace(" {} applicable for target {} (continuing evaluation)", autzHumanReadableDesc, object); + } else { + LOGGER.trace(" {} not applicable for target {}, none of the target specifications match (breaking evaluation)", + autzHumanReadableDesc, object); + continue; + } + + // authority is applicable to this situation. now we can process the decision. + AuthorizationDecisionType decision = autz.getDecision(); + if (decision == null || decision == AuthorizationDecisionType.ALLOW) { + Collection items = getItems(autz); + if (items.isEmpty()) { + LOGGER.trace(" {}: ALLOW all items (but continue evaluation)", autzHumanReadableDesc); + if (decisions.getDefaultDecision() != AuthorizationDecisionType.DENY) { + decisions.setDefaultDecision(AuthorizationDecisionType.ALLOW); + } + } else { + for(ItemPath item: items) { + LOGGER.trace(" {}: ALLOW item {} (but continue evaluation)", autzHumanReadableDesc, item); + if (decisions.getItemDecisionMap().get(item) != AuthorizationDecisionType.DENY) { + decisions.getItemDecisionMap().put(item, AuthorizationDecisionType.ALLOW); + } + } + } + } else { + Collection items = getItems(autz); + if (items.isEmpty()) { + LOGGER.trace(" {}: DENY all items (breaking evaluation)", autzHumanReadableDesc); + // Total deny. Reset everything. Return just deny + decisions = new ItemSecurityDecisions(); + decisions.setDefaultDecision(AuthorizationDecisionType.DENY); + break; + } else { + for(ItemPath item: items) { + LOGGER.trace(" {}: DENY item {} (but continue evaluation)", autzHumanReadableDesc, item); + decisions.getItemDecisionMap().put(item, AuthorizationDecisionType.DENY); + } + } + } + + } + + return decisions; + } + @Override public T runAs(Producer producer, PrismObject user) throws SchemaException { + LOGGER.debug("Running {} as {}", producer, user); Authentication origAuthentication = SecurityContextHolder.getContext().getAuthentication(); setupPreAuthenticatedSecurityContext(user);