/* * Copyright (c) 2010-2013 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.wf.impl.processors.primary.other; import com.evolveum.midpoint.model.api.context.ModelContext; import com.evolveum.midpoint.prism.Objectable; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; 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.wf.impl.processes.itemApproval.ApprovalRequest; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ApprovalRequestImpl; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ItemApprovalProcessInterface; import com.evolveum.midpoint.schema.ObjectTreeDeltas; import com.evolveum.midpoint.wf.impl.processors.primary.ModelInvocationContext; import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildWfTaskCreationInstruction; import com.evolveum.midpoint.wf.impl.processors.primary.aspect.BasePrimaryChangeAspect; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * This is a preliminary version of 'password approval' process aspect. The idea is that in some cases, a user may request * changing (resetting) his password, but if not enough authentication information is available, the change may be * subject to manual approval. * * Exact conditions should be coded into getApprovalRequestList method. Currently, we only test for ANY password change * request and push it into approval process. * * DO NOT USE THIS ASPECT IN PRODUCTION UNLESS YOU KNOW WHAT YOU ARE DOING * * @author mederly */ @Component public class ChangePasswordAspect extends BasePrimaryChangeAspect { private static final Trace LOGGER = TraceManager.getTrace(ChangePasswordAspect.class); @Autowired private PrismContext prismContext; @Autowired private ItemApprovalProcessInterface itemApprovalProcessInterface; @NotNull @Override public List<PcpChildWfTaskCreationInstruction> prepareTasks(@NotNull ObjectTreeDeltas objectTreeDeltas, ModelInvocationContext ctx, @NotNull OperationResult result) throws SchemaException { List<ApprovalRequest<String>> approvalRequestList = new ArrayList<>(); List<PcpChildWfTaskCreationInstruction> instructions = new ArrayList<>(); ObjectDelta changeRequested = objectTreeDeltas.getFocusChange(); if (changeRequested == null || changeRequested.getChangeType() != ChangeType.MODIFY) { return Collections.emptyList(); } Iterator<? extends ItemDelta> deltaIterator = changeRequested.getModifications().iterator(); ItemPath passwordPath = new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_PASSWORD, PasswordType.F_VALUE); while (deltaIterator.hasNext()) { ItemDelta delta = deltaIterator.next(); // this needs to be customized and enhanced; e.g. to start wf process only when not enough authentication info is present in the request // also, what if we replace whole 'credentials' container? if (passwordPath.equivalent(delta.getPath())) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Found password-changing delta, moving it into approval request. Delta = " + delta.debugDump()); } ApprovalRequest<String> approvalRequest = createApprovalRequest(delta, ctx.modelContext, ctx.taskFromModel, result); approvalRequestList.add(approvalRequest); instructions.add(createStartProcessInstruction(ctx.modelContext, delta, approvalRequest, ctx.taskFromModel, result)); deltaIterator.remove(); } } return instructions; } private ApprovalRequest<String> createApprovalRequest(ItemDelta delta, ModelContext<?> modelContext, Task taskFromModel, OperationResult result) { ObjectReferenceType approverRef = new ObjectReferenceType(); approverRef.setOid(SystemObjectsType.USER_ADMINISTRATOR.value()); approverRef.setType(UserType.COMPLEX_TYPE); List<ObjectReferenceType> approvers = new ArrayList<ObjectReferenceType>(); approvers.add(approverRef); ApprovalRequest<String> request = new ApprovalRequestImpl<>("Password change", null, null, approvers, Collections.emptyList(), null, prismContext); approvalSchemaHelper.prepareSchema(request.getApprovalSchemaType(), createRelationResolver((PrismObject) null, result), createReferenceResolver(modelContext, taskFromModel, result)); return request; } private PcpChildWfTaskCreationInstruction createStartProcessInstruction(ModelContext<?> modelContext, ItemDelta delta, ApprovalRequest approvalRequest, Task taskFromModel, OperationResult result) throws SchemaException { String userName = MiscDataUtil.getFocusObjectName(modelContext); String objectOid = MiscDataUtil.getFocusObjectOid(modelContext); PrismObject<UserType> requester = baseModelInvocationProcessingHelper.getRequester(taskFromModel, result); String approvalTaskName = "Approve changing password for " + userName; // create a JobCreateInstruction for a given change processor (primaryChangeProcessor in this case) PcpChildWfTaskCreationInstruction instruction = PcpChildWfTaskCreationInstruction.createItemApprovalInstruction( getChangeProcessor(), approvalTaskName, approvalRequest.getApprovalSchemaType(), null); // set some common task/process attributes instruction.prepareCommonAttributes(this, modelContext, requester); // prepare and set the delta that has to be approved instruction.setDeltasToProcess(itemDeltaToObjectDelta(objectOid, delta)); instruction.setObjectRef(modelContext, result); instruction.setTargetRef(null, result); // set the names of midPoint task and activiti process instance instruction.setTaskName("Approval of password change for " + userName); instruction.setProcessInstanceName("Changing password for " + userName); // setup general item approval process itemApprovalProcessInterface.prepareStartInstruction(instruction); return instruction; } private ObjectDelta<Objectable> itemDeltaToObjectDelta(String objectOid, ItemDelta delta) { return (ObjectDelta<Objectable>) (ObjectDelta) ObjectDelta.createModifyDelta(objectOid, delta, UserType.class, prismContext); } }