diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/page/PageBase.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/page/PageBase.java index f79f8adccc4..45fe7b5f957 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/page/PageBase.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/page/PageBase.java @@ -17,6 +17,8 @@ import com.evolveum.midpoint.web.page.admin.PageAdminObjectDetails; +import com.evolveum.midpoint.web.page.admin.certification.*; + import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.apache.commons.lang3.ObjectUtils; @@ -145,14 +147,9 @@ import com.evolveum.midpoint.web.component.util.VisibleBehaviour; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.midpoint.web.page.admin.PageAdmin; -import com.evolveum.midpoint.web.page.admin.PageAdminFocus; import com.evolveum.midpoint.web.page.admin.archetype.PageArchetype; import com.evolveum.midpoint.web.page.admin.archetype.PageArchetypes; import com.evolveum.midpoint.web.page.admin.cases.*; -import com.evolveum.midpoint.web.page.admin.certification.PageCertCampaigns; -import com.evolveum.midpoint.web.page.admin.certification.PageCertDecisions; -import com.evolveum.midpoint.web.page.admin.certification.PageCertDefinition; -import com.evolveum.midpoint.web.page.admin.certification.PageCertDefinitions; import com.evolveum.midpoint.web.page.admin.configuration.*; import com.evolveum.midpoint.web.page.admin.home.PageDashboardConfigurable; import com.evolveum.midpoint.web.page.admin.home.PageDashboardInfo; @@ -658,6 +655,16 @@ public boolean isAuthorized(ModelAuthorizationAction acti } } + // TODO reconsider this method + public boolean isFullyAuthorized() { + try { + return isAuthorized(AuthorizationConstants.AUTZ_ALL_URL); + } catch (Throwable t) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't check the authorization", t); + return false; + } + } + public boolean isAuthorized(String operationUrl) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { return isAuthorized(operationUrl, null, null, null, null, null); } @@ -1953,6 +1960,9 @@ public String getBubbleLabel() { PageTasksCertScheduling.class, params, null); item.getItems().add(menu); + if (isFullyAuthorized()) { // workaround for MID-5917 + addMenuItem(item, "PageAdmin.menu.top.certification.allDecisions", PageCertDecisionsAll.class); + } addMenuItem(item, "PageAdmin.menu.top.certification.decisions", PageCertDecisions.class); MenuItem newCertificationMenu = new MenuItem(createStringResource("PageAdmin.menu.top.certification.newDefinition"), GuiStyleConstants.CLASS_PLUS_CIRCLE, PageCertDefinition.class, null, diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/certification/PageCertDecisions.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/certification/PageCertDecisions.java index 0274f5949c8..e0bd6bce198 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/certification/PageCertDecisions.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/certification/PageCertDecisions.java @@ -57,7 +57,6 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.request.mapper.parameter.PageParameters; -import org.apache.xpath.operations.Bool; import javax.xml.datatype.XMLGregorianCalendar; import java.util.ArrayList; @@ -68,9 +67,6 @@ import static com.evolveum.midpoint.web.page.admin.certification.CertDecisionHelper.WhichObject.TARGET; import static com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationResponseType.*; -/** - * @author mederly - */ @PageDescriptor(url = "/admin/certification/decisions", action = { @AuthorizationAction(actionUri = PageAdminCertification.AUTH_CERTIFICATION_ALL, @@ -97,6 +93,10 @@ public class PageCertDecisions extends PageAdminCertification { private CertDecisionHelper helper = new CertDecisionHelper(); + boolean isDisplayingAllItems() { + return false; + } + public PageCertDecisions() { } @@ -112,6 +112,8 @@ private CertWorkItemDtoProvider createProvider() { provider.setQuery(createCaseQuery()); provider.setCampaignQuery(createCampaignQuery()); provider.setReviewerOid(getCurrentUserOid()); + provider.setNotDecidedOnly(getCertDecisionsStorage().getShowNotDecidedOnly()); + provider.setAllItems(isDisplayingAllItems()); provider.setSort(SearchingUtils.CURRENT_REVIEW_DEADLINE, SortOrder.ASCENDING); // default sorting return provider; } @@ -518,7 +520,8 @@ private void searchFilterPerformed(AjaxRequestTarget target) { DataTable table = panel.getDataTable(); CertWorkItemDtoProvider provider = (CertWorkItemDtoProvider) table.getDataProvider(); provider.setQuery(query); - provider.setNotDecidedOnly(getCertDecisionsStorage().getShowNotDecidedOnly().booleanValue()); + provider.setNotDecidedOnly(getCertDecisionsStorage().getShowNotDecidedOnly()); + provider.setAllItems(isDisplayingAllItems()); table.setCurrentPage(0); target.add(getFeedbackPanel()); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/certification/PageCertDecisionsAll.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/certification/PageCertDecisionsAll.java new file mode 100644 index 00000000000..32c7cc6b945 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/certification/PageCertDecisionsAll.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.web.page.admin.certification; + +import com.evolveum.midpoint.web.application.AuthorizationAction; +import com.evolveum.midpoint.web.application.PageDescriptor; + +/** + * Displays all certification decisions. + * + * Note: The ultimate authorization check is done in certification-impl module. + */ +@PageDescriptor(url = "/admin/certification/decisionsAll", + action = { + @AuthorizationAction(actionUri = PageAdminCertification.AUTH_CERTIFICATION_ALL, + label = PageAdminCertification.AUTH_CERTIFICATION_ALL_LABEL, + description = PageAdminCertification.AUTH_CERTIFICATION_ALL_DESCRIPTION), + @AuthorizationAction(actionUri = PageAdminCertification.AUTH_CERTIFICATION_DECISIONS, + label = PageAdminCertification.AUTH_CERTIFICATION_DECISIONS_LABEL, + description = PageAdminCertification.AUTH_CERTIFICATION_DECISIONS_DESCRIPTION)}) +public class PageCertDecisionsAll extends PageCertDecisions { + + @Override + boolean isDisplayingAllItems() { + return true; + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/certification/dto/CertWorkItemDtoProvider.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/certification/dto/CertWorkItemDtoProvider.java index 6b1f5d7136b..2a80eb8db27 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/certification/dto/CertWorkItemDtoProvider.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/certification/dto/CertWorkItemDtoProvider.java @@ -7,7 +7,6 @@ package com.evolveum.midpoint.web.page.admin.certification.dto; -import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.model.api.AccessCertificationService; import com.evolveum.midpoint.prism.query.ObjectOrdering; import com.evolveum.midpoint.prism.query.ObjectPaging; @@ -20,10 +19,8 @@ import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.data.BaseSortableDataProvider; -import com.evolveum.midpoint.web.page.error.PageError; import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationWorkItemType; import org.apache.wicket.Component; -import org.apache.wicket.RestartResponseException; import org.apache.wicket.extensions.markup.html.repeater.util.SortParam; import org.jetbrains.annotations.NotNull; @@ -50,6 +47,7 @@ public class CertWorkItemDtoProvider extends BaseSortableDataProvider internalIterator(long first, long count) { Collection> resolveNames = createCollection(createResolveNames()); AccessCertificationService acs = getPage().getCertificationService(); - List workitems = acs.searchOpenWorkItems(caseQuery, notDecidedOnly, resolveNames, task, result); + List workitems = acs.searchOpenWorkItems(caseQuery, notDecidedOnly, allItems, resolveNames, task, result); for (AccessCertificationWorkItemType workItem : workitems) { getAvailableData().add(new CertWorkItemDto(workItem, getPage())); } @@ -88,11 +86,6 @@ public Iterator internalIterator(long first, long count) { return getAvailableData().iterator(); } - private void handleNotSuccessOrHandledErrorInIterator(OperationResult result) { - getPage().showResult(result); - throw new RestartResponseException(PageError.class); - } - @Override protected int internalSize() { LOGGER.trace("begin::internalSize()"); @@ -102,7 +95,7 @@ protected int internalSize() { Task task = getPage().createSimpleTask(OPERATION_COUNT_OBJECTS); AccessCertificationService acs = getPage().getCertificationService(); ObjectQuery query = getQuery().clone(); - count = acs.countOpenWorkItems(query, notDecidedOnly, null, task, result); + count = acs.countOpenWorkItems(query, notDecidedOnly, allItems,null, task, result); } catch (Exception ex) { result.recordFatalError( getPage().createStringResource("CertWorkItemDtoProvider.message.internalSize.fatalError", ex.getMessage()).getString(), ex); @@ -150,4 +143,7 @@ protected List createObjectOrderings(SortParam sortParam return SearchingUtils.createObjectOrderings(sortParam, true, getPrismContext()); } + public void setAllItems(boolean allItems) { + this.allItems = allItems; + } } diff --git a/model/certification-api/src/main/java/com/evolveum/midpoint/certification/api/CertificationManager.java b/model/certification-api/src/main/java/com/evolveum/midpoint/certification/api/CertificationManager.java index d81fa883083..928151dff2e 100644 --- a/model/certification-api/src/main/java/com/evolveum/midpoint/certification/api/CertificationManager.java +++ b/model/certification-api/src/main/java/com/evolveum/midpoint/certification/api/CertificationManager.java @@ -54,7 +54,6 @@ public interface CertificationManager { * @param task Task in context of which all operations will take place. * @param parentResult Result for the operations. * @return Object for the created campaign. It will be stored in the repository as well. - * @throws ExpressionEvaluationException */ AccessCertificationCampaignType createCampaign(String definitionOid, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException; @@ -87,19 +86,11 @@ AccessCertificationCampaignType createCampaign(String definitionOid, Task task, /** * Starts the remediation phase for the campaign. * The campaign has to be in the last stage and that stage has to be already closed. - * - * @param campaignOid - * @param task - * @param result */ void startRemediation(String campaignOid, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException; /** * Closes a campaign. - * - * @param campaignOid - * @param task - * @param result */ void closeCampaign(String campaignOid, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException; @@ -135,28 +126,41 @@ List searchDecisionsToReview(ObjectQuery caseQuery, throws ObjectNotFoundException, SchemaException, SecurityViolationException; /** - * Returns a set of certification work items for currently logged-in user. + * Returns a set of certification work items for currently logged-in user (or all users). * Query argument for cases is the same as in the model.searchContainers(AccessCertificationCaseType...) call. * * @param caseQuery Specification of the cases to retrieve. * @param notDecidedOnly If true, only response==(NO_DECISION or null) should be returned. * Although it can be formulated in Query API terms, this would refer to implementation details - so * the cleaner way is keep this knowledge inside certification module only. + * @param allItems If true, retrieves work items for all users. Requires root ("ALL") authorization. * @param options Options to use (e.g. RESOLVE_NAMES). * @param task Task in context of which all operations will take place. * @param parentResult Result for the operations. * @return A list of relevant certification cases. - * @throws ExpressionEvaluationException * */ - List searchOpenWorkItems(ObjectQuery caseQuery, boolean notDecidedOnly, + List searchOpenWorkItems(ObjectQuery caseQuery, boolean notDecidedOnly, boolean allItems, Collection> options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException; - int countOpenWorkItems(ObjectQuery caseQuery, boolean notDecidedOnly, + default List searchOpenWorkItems(ObjectQuery caseQuery, boolean notDecidedOnly, + Collection> options, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + return searchOpenWorkItems(caseQuery, notDecidedOnly, false, options, task, parentResult); + } + + int countOpenWorkItems(ObjectQuery caseQuery, boolean notDecidedOnly, boolean allItems, Collection> options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException; + @SuppressWarnings("unused") + default int countOpenWorkItems(ObjectQuery caseQuery, boolean notDecidedOnly, + Collection> options, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + return countOpenWorkItems(caseQuery, notDecidedOnly, false, options, task, parentResult); + } + /** * Records a particular decision of a reviewer. * @param campaignOid OID of the campaign to which the decision belongs. diff --git a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/CertificationManagerImpl.java b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/CertificationManagerImpl.java index db0e783df8f..0b472a423b9 100644 --- a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/CertificationManagerImpl.java +++ b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/CertificationManagerImpl.java @@ -24,6 +24,8 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.CertCampaignTypeUtil; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.security.api.SecurityContextManager; import com.evolveum.midpoint.security.api.SecurityUtil; import com.evolveum.midpoint.security.enforcer.api.AuthorizationParameters; @@ -343,16 +345,13 @@ public List searchDecisionsToReview(ObjectQuery cas @Override public List searchOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, - Collection> options, Task task, OperationResult parentResult) + boolean allItems, Collection> options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { OperationResult result = parentResult.createSubresult(OPERATION_SEARCH_OPEN_WORK_ITEMS); - try { - securityEnforcer.authorize(ModelAuthorizationAction.READ_OWN_CERTIFICATION_DECISIONS.getUrl(), null, - AuthorizationParameters.EMPTY, null, task, result); - - return queryHelper.searchOpenWorkItems(baseWorkItemsQuery, SecurityUtil.getPrincipal(), notDecidedOnly, options, result); + MidPointPrincipal principal = getAuthorizedPrincipal(allItems, task, result); + return queryHelper.searchOpenWorkItems(baseWorkItemsQuery, principal, notDecidedOnly, options, result); } catch (RuntimeException e) { result.recordFatalError("Couldn't search for certification work items: unexpected exception: " + e.getMessage(), e); throw e; @@ -361,18 +360,36 @@ public List searchOpenWorkItems(ObjectQuery bas } } + @Nullable + private MidPointPrincipal getAuthorizedPrincipal(boolean allItems, Task task, OperationResult result) + throws SecurityViolationException, SchemaException, ObjectNotFoundException, ExpressionEvaluationException, + CommunicationException, ConfigurationException { + if (allItems) { + securityEnforcer.authorize(AuthorizationConstants.AUTZ_ALL_URL, null, + AuthorizationParameters.EMPTY, null, task, result); + return null; + } else { + securityEnforcer.authorize(ModelAuthorizationAction.READ_OWN_CERTIFICATION_DECISIONS.getUrl(), null, + AuthorizationParameters.EMPTY, null, task, result); + MidPointPrincipal principal = SecurityUtil.getPrincipal(); + if (principal == null) { + throw new IllegalStateException("No principal"); + } else { + return principal; + } + } + } + @Override - public int countOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, + public int countOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, boolean allItems, Collection> options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { OperationResult result = parentResult.createSubresult(OPERATION_COUNT_OPEN_WORK_ITEMS); try { - securityEnforcer.authorize(ModelAuthorizationAction.READ_OWN_CERTIFICATION_DECISIONS.getUrl(), null, - AuthorizationParameters.EMPTY, null, task, result); - - return queryHelper.countOpenWorkItems(baseWorkItemsQuery, SecurityUtil.getPrincipal(), notDecidedOnly, options, result); + MidPointPrincipal principal = getAuthorizedPrincipal(allItems, task, result); + return queryHelper.countOpenWorkItems(baseWorkItemsQuery, principal, notDecidedOnly, options, result); } catch (RuntimeException e) { result.recordFatalError("Couldn't search for certification work items: unexpected exception: " + e.getMessage(), e); throw e; diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/AccessCertificationService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/AccessCertificationService.java index 3e7d29e74ab..024f658a139 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/AccessCertificationService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/AccessCertificationService.java @@ -89,19 +89,11 @@ AccessCertificationCampaignType createCampaign(String definitionOid, Task task, /** * Starts the remediation phase for the campaign. * The campaign has to be in the last stage and that stage has to be already closed. - * - * @param campaignOid - * @param task - * @param result */ void startRemediation(String campaignOid, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException; /** * Closes a campaign. - * - * @param campaignOid - * @param task - * @param result */ void closeCampaign(String campaignOid, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException; @@ -126,20 +118,33 @@ AccessCertificationCampaignType createCampaign(String definitionOid, Task task, * @param notDecidedOnly If true, only response==(NO_DECISION or null) should be returned. * Although it can be formulated in Query API terms, this would refer to implementation details - so * the cleaner way is keep this knowledge inside certification module only. + * @param allItems If true, returns items for all users (requires "ALL" authorization). * @param options Options to use (e.g. RESOLVE_NAMES). * @param task Task in context of which all operations will take place. * @param parentResult Result for the operations. * @return A list of relevant certification cases. * */ - List searchOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, + List searchOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, boolean allItems, Collection> options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, CommunicationException, ExpressionEvaluationException; - int countOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, + default List searchOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, + Collection> options, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, CommunicationException, ExpressionEvaluationException { + return searchOpenWorkItems(baseWorkItemsQuery, notDecidedOnly, false, options, task, parentResult); + } + + int countOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, boolean allItems, Collection> options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, CommunicationException, ExpressionEvaluationException; + default int countOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, + Collection> options, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, CommunicationException, ExpressionEvaluationException { + return countOpenWorkItems(baseWorkItemsQuery, notDecidedOnly, false, options, task, parentResult); + } + /** * Records a particular decision of a reviewer. * diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java index 1669d93ca42..3c2c6a74d65 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java @@ -2172,16 +2172,20 @@ public void recordDecision(String campaignOid, long caseId, long workItemId, Acc @Deprecated @Override - public List searchOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, Collection> rawOptions, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + public List searchOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, + boolean allItems, Collection> rawOptions, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, + ConfigurationException { Collection> options = preProcessOptionsSecurity(rawOptions, task, parentResult); - return getCertificationManagerChecked().searchOpenWorkItems(baseWorkItemsQuery, notDecidedOnly, options, task, parentResult); + return getCertificationManagerChecked().searchOpenWorkItems(baseWorkItemsQuery, notDecidedOnly, allItems, options, task, parentResult); } @Deprecated @Override - public int countOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, Collection> rawOptions, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + public int countOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, boolean allItems, + Collection> rawOptions, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { Collection> options = preProcessOptionsSecurity(rawOptions, task, parentResult); - return getCertificationManagerChecked().countOpenWorkItems(baseWorkItemsQuery, notDecidedOnly, options, task, parentResult); + return getCertificationManagerChecked().countOpenWorkItems(baseWorkItemsQuery, notDecidedOnly, allItems, options, task, parentResult); } @Override diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/FocusProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/FocusProcessor.java index bd565579daf..47db3bd35c2 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/FocusProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/FocusProcessor.java @@ -141,39 +141,27 @@ private void processAssignmentActivation(LensCo // We care only about existing assignments here. New assignments will be taken care of in the executor // (OperationalDataProcessor). And why care about deleted assignments? Collection> zeroSet = evaluatedAssignmentTriple.getZeroSet(); - if (zeroSet == null) { - return; - } LensFocusContext focusContext = context.getFocusContext(); for (EvaluatedAssignmentImpl evaluatedAssignment: zeroSet) { if (evaluatedAssignment.isVirtual()) { continue; } - AssignmentType assignmentType = evaluatedAssignment.getAssignmentType(); - ActivationType currentActivationType = assignmentType.getActivation(); - ActivationStatusType expectedEffectiveStatus = activationComputer.getEffectiveStatus(assignmentType.getLifecycleState(), currentActivationType, null); - if (currentActivationType == null) { - PrismContainerDefinition activationDef = focusContext.getObjectDefinition().findContainerDefinition(SchemaConstants.PATH_ASSIGNMENT_ACTIVATION); - ContainerDelta activationDelta = activationDef.createEmptyDelta( - ItemPath.create(FocusType.F_ASSIGNMENT, assignmentType.getId(), AssignmentType.F_ACTIVATION)); - ActivationType newActivationType = new ActivationType(); - activationDelta.setValuesToReplace(newActivationType.asPrismContainerValue()); - newActivationType.setEffectiveStatus(expectedEffectiveStatus); - focusContext.swallowToSecondaryDelta(activationDelta); - } else { - ActivationStatusType currentEffectiveStatus = currentActivationType.getEffectiveStatus(); - if (!expectedEffectiveStatus.equals(currentEffectiveStatus)) { - PrismPropertyDefinition effectiveStatusPropertyDef = focusContext.getObjectDefinition().findPropertyDefinition(SchemaConstants.PATH_ASSIGNMENT_ACTIVATION_EFFECTIVE_STATUS); - PropertyDelta effectiveStatusDelta = effectiveStatusPropertyDef.createEmptyDelta( - ItemPath.create(FocusType.F_ASSIGNMENT, assignmentType.getId(), AssignmentType.F_ACTIVATION, ActivationType.F_EFFECTIVE_STATUS)); - effectiveStatusDelta.setRealValuesToReplace(expectedEffectiveStatus); - focusContext.swallowToSecondaryDelta(effectiveStatusDelta); - } + AssignmentType assignment = evaluatedAssignment.getAssignmentType(); + ActivationType currentActivation = assignment.getActivation(); + ActivationStatusType currentEffectiveStatus = currentActivation != null ? currentActivation.getEffectiveStatus() : null; + ActivationStatusType expectedEffectiveStatus = activationComputer.getEffectiveStatus(assignment.getLifecycleState(), + currentActivation, null); + if (currentEffectiveStatus != expectedEffectiveStatus) { + PrismPropertyDefinition effectiveStatusPropertyDef = focusContext.getObjectDefinition() + .findPropertyDefinition(SchemaConstants.PATH_ASSIGNMENT_ACTIVATION_EFFECTIVE_STATUS); + PropertyDelta effectiveStatusDelta = effectiveStatusPropertyDef.createEmptyDelta( + ItemPath.create(FocusType.F_ASSIGNMENT, assignment.getId(), AssignmentType.F_ACTIVATION, ActivationType.F_EFFECTIVE_STATUS)); + effectiveStatusDelta.setRealValuesToReplace(expectedEffectiveStatus); + focusContext.swallowToSecondaryDelta(effectiveStatusDelta); } } } - private void processActivationAdministrativeAndValidity(LensFocusContext focusContext, XMLGregorianCalendar now, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException { diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestNotifications.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestNotifications.java index c67919a5f1d..fe46cdfa551 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestNotifications.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestNotifications.java @@ -22,6 +22,7 @@ import com.evolveum.midpoint.schema.util.MiscSchemaUtil; import com.evolveum.midpoint.task.api.LightweightIdentifierGenerator; import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.test.TestResource; import com.evolveum.midpoint.test.util.TestUtil; import com.evolveum.midpoint.util.exception.CommonException; import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; @@ -60,6 +61,9 @@ public class TestNotifications extends AbstractInitializedModelIntegrationTest { public static final File TEST_DIR = new File("src/test/resources/notifications"); private static final File SYSTEM_CONFIGURATION_FILE = new File(TEST_DIR, "system-configuration.xml"); + private static final TestResource ARCHETYPE_DUMMY = new TestResource(TEST_DIR, "archetype-dummy.xml", "c97780b7-6b07-4a25-be95-60125af6f650"); + private static final TestResource ROLE_DUMMY = new TestResource(TEST_DIR, "role-dummy.xml", "8bc6d827-6ea6-4671-a506-a8388f117880"); + @Autowired private LightweightIdentifierGenerator lightweightIdentifierGenerator; private String accountJackOid; @@ -67,9 +71,10 @@ public class TestNotifications extends AbstractInitializedModelIntegrationTest { private MyHttpHandler httpHandler; @Override - public void initSystem(Task initTask, OperationResult initResult) - throws Exception { + public void initSystem(Task initTask, OperationResult initResult) throws Exception { super.initSystem(initTask, initResult); + repoAdd(ARCHETYPE_DUMMY, initResult); + repoAdd(ROLE_DUMMY, initResult); InternalMonitor.reset(); } @@ -625,7 +630,7 @@ public void test220SendSmsViaProxy() { assertNotNull("No http request found", httpHandler.lastRequest); assertEquals("Wrong HTTP method", "GET", httpHandler.lastRequest.method); - assertTrue("Header proxy-connection not found in request headers", httpHandler.lastRequest.headers.keySet().contains("proxy-connection")); + assertTrue("Header proxy-connection not found in request headers", httpHandler.lastRequest.headers.containsKey("proxy-connection")); assertEquals("Wrong proxy-connection header", "Keep-Alive", httpHandler.lastRequest.headers.get("proxy-connection").get(0)); } @@ -728,7 +733,7 @@ public void test410ByteAttachment() throws Exception { byte[] origJPEG = Base64.getDecoder().decode(origJPEGString); Object content = RawType.getValue(message.getAttachments().get(0).getContent()); if(!(content instanceof byte[]) || !Arrays.equals(origJPEG, (byte[])content)) { - throw new AssertionError("Wrong content of attachments expected:" + origJPEG + " but was:" + content); + throw new AssertionError("Wrong content of attachments expected:" + Arrays.toString(origJPEG) + " but was:" + content); } assertEquals("Wrong fileName of attachments", "alf.jpg", message.getAttachments().get(0).getFileName()); assertNull("Wrong fileName of attachments", message.getAttachments().get(0).getContentFromFile()); @@ -764,7 +769,7 @@ public void test420AttachmentFromFile() throws Exception { assertEquals("Wrong contentType of attachment", "image/png", message.getAttachments().get(0).getContentType()); assertEquals("Wrong fileName of attachments", "alf.png", message.getAttachments().get(0).getFileName()); assertEquals("Wrong fileName of attachments", "/home/user/example.png", message.getAttachments().get(0).getContentFromFile()); - assertEquals("Wrong fileName of attachments", null, message.getAttachments().get(0).getContent()); + assertNull("Wrong fileName of attachments", message.getAttachments().get(0).getContent()); } @Test @@ -797,11 +802,48 @@ public void test430ExpressionAttachment() throws Exception { assertEquals("Wrong contentType of attachment", "text/html", message.getAttachments().get(0).getContentType()); assertEquals("Wrong content of attachments", "Hello World!", message.getAttachments().get(0).getContent()); assertEquals("Wrong fileName of attachments", "hello_world.html", message.getAttachments().get(0).getFileName()); - assertEquals("Wrong fileName of attachments", null, message.getAttachments().get(0).getContentFromFile()); + assertNull("Wrong fileName of attachments", message.getAttachments().get(0).getContentFromFile()); } // TODO binary attachment, attachment from file, attachment from expression + /** + * MID-5350 + */ + @Test + public void test500RecomputeRole() throws Exception { + + setGlobalTracingOverride(addNotificationsLogging(createModelLoggingTracingProfile())); + + given(); + Task task = getTestTask(); + OperationResult result = task.getResult(); + preTestCleanup(AssignmentPolicyEnforcementType.FULL); + + when(); + recomputeFocus(RoleType.class, ROLE_DUMMY.oid, task, result); + + then(); + result.computeStatus(); + TestUtil.assertSuccess("executeChanges result", result); + + // Check notifications + display("Notifications", dummyTransport); + + notificationManager.setDisabled(true); + checkDummyTransportMessages("simpleRoleNotifier", 0); // MID-5350 (other asserts are just for sure) + checkDummyTransportMessages("accountPasswordNotifier", 0); + checkDummyTransportMessages("userPasswordNotifier", 0); + checkDummyTransportMessages("simpleAccountNotifier-SUCCESS", 0); + checkDummyTransportMessages("simpleAccountNotifier-FAILURE", 0); + checkDummyTransportMessages("simpleAccountNotifier-ADD-SUCCESS", 0); + checkDummyTransportMessages("simpleAccountNotifier-DELETE-SUCCESS", 0); + checkDummyTransportMessages("simpleUserNotifier", 0); + checkDummyTransportMessages("simpleUserNotifier-ADD", 0); + + assertSteadyResources(); + } + @SuppressWarnings("Duplicates") private void preTestCleanup(AssignmentPolicyEnforcementType enforcementPolicy) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { assumeAssignmentPolicy(enforcementPolicy); @@ -813,11 +855,11 @@ private void preTestCleanup(AssignmentPolicyEnforcementType enforcementPolicy) t private static class MyHttpHandler implements HttpHandler { - private class Request { - URI uri; - String method; - Map> headers; - List body; + private static class Request { + private URI uri; + private String method; + private Map> headers; + private List body; } private Request lastRequest; diff --git a/model/model-intest/src/test/resources/notifications/archetype-dummy.xml b/model/model-intest/src/test/resources/notifications/archetype-dummy.xml new file mode 100644 index 00000000000..60d11e77d7e --- /dev/null +++ b/model/model-intest/src/test/resources/notifications/archetype-dummy.xml @@ -0,0 +1,12 @@ + + + + + archetype-dummy + diff --git a/model/model-intest/src/test/resources/notifications/role-dummy.xml b/model/model-intest/src/test/resources/notifications/role-dummy.xml new file mode 100644 index 00000000000..03097900d98 --- /dev/null +++ b/model/model-intest/src/test/resources/notifications/role-dummy.xml @@ -0,0 +1,25 @@ + + + + + role-dummy + Dummy + + + + + + + + + + dummy + diff --git a/model/model-intest/src/test/resources/notifications/system-configuration.xml b/model/model-intest/src/test/resources/notifications/system-configuration.xml index e2fc724fd03..bd66ca4b467 100644 --- a/model/model-intest/src/test/resources/notifications/system-configuration.xml +++ b/model/model-intest/src/test/resources/notifications/system-configuration.xml @@ -143,6 +143,21 @@ Channel: $!event.channel dummy:simpleUserNotifier + + + + recipient@evolveum.com + + + + + dummy:simpleRoleNotifier + + add diff --git a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/Event.java b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/Event.java index 186b323c842..b7a5e389a85 100644 --- a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/Event.java +++ b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/Event.java @@ -97,7 +97,7 @@ default String getRequesteeOid() { boolean isOperationType(EventOperationType eventOperation); /** - * @return true if the categoru of the event matches the specified one + * @return true if the category of the event matches the specified one */ boolean isCategoryType(EventCategoryType eventCategory); diff --git a/model/notifications-impl/src/test/java/com/evolveum/midpoint/notifications/impl/TestTextFormatter.java b/model/notifications-impl/src/test/java/com/evolveum/midpoint/notifications/impl/TestTextFormatter.java index 6235c8e4d0a..ee84e984c39 100644 --- a/model/notifications-impl/src/test/java/com/evolveum/midpoint/notifications/impl/TestTextFormatter.java +++ b/model/notifications-impl/src/test/java/com/evolveum/midpoint/notifications/impl/TestTextFormatter.java @@ -21,7 +21,7 @@ import com.evolveum.midpoint.schema.constants.ObjectTypes; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; -import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; @@ -42,9 +42,6 @@ import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ObjectModificationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; /** * @@ -298,6 +295,48 @@ public void test050FormatDeltaWithOperAndAuxItems() throws Exception { } + /** + * Delta formatter cannot correctly deal with a situation when we are replacing empty container value with one + * that contains only hidden items. + * + * An example: + * - BEFORE: assignment[1]/activation = (empty) + * - DELTA: REPLACE assignment[1]/activation with (effectiveStatus: ENABLED) -- i.e. with seemingly empty PCV + * + * We should hide such modification. But we do not do this now. (See MID-5350.) + * + * We fixed that issue by changing the delta that is created. + * But this behavior of delta formatter should be eventually fixed. See MID-6111. + */ + @Test(enabled = false) + public void test060FormatDeltaWithSingleOperationalItemContainer() throws Exception { + + given(); + + PrismObject jack = PrismTestUtil.parseObject(new File(USER_JACK_FILE)); + display("jack", jack.debugDump()); + + // @formatter:off + ObjectDelta delta = prismContext.deltaFor(UserType.class) + .item(UserType.F_ACTIVATION, ActivationType.F_EFFECTIVE_STATUS) + .replace(ActivationStatusType.ENABLED) + // see MID-5350 + .item(UserType.F_ASSIGNMENT, 1, UserType.F_ACTIVATION) + .replace(new ActivationType(prismContext).effectiveStatus(ActivationStatusType.ENABLED)) + .asObjectDelta("some-user-oid"); + // @formatter:on + + display("delta", delta.debugDump()); + + when(); + + boolean hasVisible = textFormatter.containsVisibleModifiedItems(delta.getModifications(), false, false); + + then(); + + assertFalse("There should be no visible modified items", hasVisible); + } + @SuppressWarnings("SameParameterValue") private ObjectDelta parseDelta(String filename) throws SchemaException, IOException { ObjectModificationType modElement = PrismTestUtil.parseAtomicValue(new File(filename), ObjectModificationType.COMPLEX_TYPE);