Skip to content

Commit

Permalink
Ad hoc certifications.
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed Apr 24, 2017
1 parent 74465db commit ab5f5e5
Show file tree
Hide file tree
Showing 18 changed files with 451 additions and 47 deletions.
Expand Up @@ -30,7 +30,9 @@
import java.io.Serializable;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* The triple of values (added, unchanged, deleted) that represents difference between two collections of values.
Expand Down Expand Up @@ -295,6 +297,11 @@ public Collection<T> getAllValues() {
return allValues;
}

public Stream<T> stream() {
// concatenates the streams
return Stream.of(zeroSet.stream(), plusSet.stream(), minusSet.stream()).flatMap(Function.identity());
}

private void addAllValuesSet(Collection<T> allValues, Collection<T> set) {
if (set == null) {
return;
Expand Down
Expand Up @@ -18,7 +18,6 @@

import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.util.exception.SchemaException;

/**
* @author mederly
Expand Down
Expand Up @@ -283,6 +283,16 @@
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<!--<xsd:element name="targetType" type="xsd:QName" minOccurs="0" maxOccurs="unbounded">-->
<!--<xsd:annotation>-->
<!--<xsd:documentation>-->
<!--This policy only applies to targets of the specified type.-->
<!--</xsd:documentation>-->
<!--<xsd:appinfo>-->
<!--<a:since>3.6</a:since>-->
<!--</xsd:appinfo>-->
<!--</xsd:annotation>-->
<!--</xsd:element>-->
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
Expand Down Expand Up @@ -796,7 +806,19 @@
<xsd:complexContent>
<xsd:extension base="tns:PolicyActionType">
<xsd:sequence>
<!-- TODO -->
<xsd:element name="definitionRef" type="c:ObjectReferenceType" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
<p>
Certification definition(s) to be started as part of the action execution.
</p>
</xsd:documentation>
<xsd:appinfo>
<a:objectReferenceTargetType>tns:AccessCertificationDefinitionType</a:objectReferenceTargetType>
<a:since>3.6</a:since>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
Expand Down
Expand Up @@ -30,7 +30,11 @@
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.delta.PropertyDelta;
import com.evolveum.midpoint.prism.delta.builder.DeltaBuilder;
import com.evolveum.midpoint.prism.marshaller.QueryConvertor;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.query.builder.QueryBuilder;
import com.evolveum.midpoint.prism.util.CloneUtil;
import com.evolveum.midpoint.prism.util.PrismUtil;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
Expand Down Expand Up @@ -110,7 +114,8 @@ public class AccCertUpdateHelper {
//region ================================ Campaign create ================================

AccessCertificationCampaignType createCampaignObject(AccessCertificationDefinitionType definition,
Task task, OperationResult result) throws SecurityViolationException, SchemaException, ObjectNotFoundException {
Task task, OperationResult result)
throws SchemaException, ObjectNotFoundException, SecurityViolationException {
AccessCertificationCampaignType newCampaign = new AccessCertificationCampaignType(prismContext);

if (definition.getName() != null) {
Expand Down Expand Up @@ -146,7 +151,28 @@ AccessCertificationCampaignType createCampaignObject(AccessCertificationDefiniti
return newCampaign;
}

private PolyStringType generateCampaignName(AccessCertificationDefinitionType definition, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException {
<O extends ObjectType> AccessCertificationCampaignType createAdHocCampaignObject(
AccessCertificationDefinitionType definition, PrismObject<O> focus, Task task,
OperationResult result) throws SecurityViolationException, ObjectNotFoundException, SchemaException {
definition.setName(PolyStringType.fromOrig(PolyString.getOrig(definition.getName()) + " " + PolyString.getOrig(focus.getName())));
definition.setLastCampaignIdUsed(null);
AccessCertificationCampaignType campaign = createCampaignObject(definition, task, result);
AccessCertificationObjectBasedScopeType scope;
if ((campaign.getScopeDefinition() instanceof AccessCertificationObjectBasedScopeType)) {
scope = (AccessCertificationObjectBasedScopeType) campaign.getScopeDefinition();
} else {
// TODO!
scope = new AccessCertificationAssignmentReviewScopeType(prismContext);
campaign.setScopeDefinition(scope);
}
Class<? extends ObjectType> focusClass = focus.asObjectable().getClass();
scope.setObjectType(ObjectTypes.getObjectType(focusClass).getTypeQName());
ObjectFilter objectFilter = QueryBuilder.queryFor(focusClass, prismContext).id(focus.getOid()).buildFilter();
scope.setSearchFilter(QueryConvertor.createSearchFilterType(objectFilter, prismContext));
return campaign;
}

private PolyStringType generateCampaignName(AccessCertificationDefinitionType definition, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException {
String prefix = definition.getName().getOrig();
Integer lastCampaignIdUsed = definition.getLastCampaignIdUsed() != null ? definition.getLastCampaignIdUsed() : 0;
for (int i = lastCampaignIdUsed+1;; i++) {
Expand Down Expand Up @@ -710,5 +736,5 @@ public AccessCertificationCampaignType refreshCampaign(AccessCertificationCampai
return repositoryService.getObject(AccessCertificationCampaignType.class, campaign.getOid(), null, result).asObjectable();
}

//endregion
//endregion
}
@@ -0,0 +1,120 @@
/*
* 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.
* 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.certification.impl;

import com.evolveum.midpoint.model.api.context.EvaluatedAssignment;
import com.evolveum.midpoint.model.api.context.EvaluatedPolicyRule;
import com.evolveum.midpoint.model.api.context.ModelContext;
import com.evolveum.midpoint.model.api.context.ModelState;
import com.evolveum.midpoint.model.api.hooks.ChangeHook;
import com.evolveum.midpoint.model.api.hooks.HookOperationMode;
import com.evolveum.midpoint.model.api.hooks.HookRegistry;
import com.evolveum.midpoint.model.impl.lens.LensElementContext;
import com.evolveum.midpoint.prism.delta.DeltaSetTriple;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.CommonException;
import com.evolveum.midpoint.util.exception.PolicyViolationException;
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.CertificationPolicyActionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
* Starts ad-hoc certifications as prescribed by "certificate" policy action.
*
* @author mederly
*/
@Component
public class CertificationHook implements ChangeHook {

private static final Trace LOGGER = TraceManager.getTrace(CertificationHook.class);

private static final String HOOK_URI = SchemaConstants.NS_MODEL + "/certification-hook-3";

@Autowired private HookRegistry hookRegistry;
@Autowired private CertificationManagerImpl certificationManager;
@Autowired private AccCertUpdateHelper updateHelper;

@PostConstruct
public void init() {
hookRegistry.registerChangeHook(HOOK_URI, this);
LOGGER.trace("CertificationHook registered.");
}

@Override
public <O extends ObjectType> HookOperationMode invoke(@NotNull ModelContext<O> context, @NotNull Task task,
@NotNull OperationResult result) throws PolicyViolationException {
if (context.getState() != ModelState.FINAL) {
return HookOperationMode.FOREGROUND;
}
LensElementContext<O> focusContext = (LensElementContext<O>) context.getFocusContext();
if (focusContext == null || !FocusType.class.isAssignableFrom(focusContext.getObjectTypeClass())) {
return HookOperationMode.FOREGROUND;
}
List<CertificationPolicyActionType> actions = new ArrayList<>();
actions.addAll(getFocusCertificationActions(context));
actions.addAll(getAssignmentCertificationActions(context));
try {
certificationManager.startAdHocCertifications(focusContext.getObjectAny(), actions, task, result);
} catch (CommonException e) {
throw new SystemException("Couldn't start ad-hoc campaign(s): " + e.getMessage(), e);
}
return HookOperationMode.FOREGROUND;
}

private Collection<CertificationPolicyActionType> getFocusCertificationActions(ModelContext<?> context) {
return getCertificationActions(context.getFocusContext().getPolicyRules());
}

private Collection<CertificationPolicyActionType> getAssignmentCertificationActions(ModelContext<?> context) {
DeltaSetTriple<? extends EvaluatedAssignment<?>> evaluatedAssignmentTriple = context.getEvaluatedAssignmentTriple();
if (evaluatedAssignmentTriple == null) {
return Collections.emptyList();
} else {
return evaluatedAssignmentTriple.stream()
.flatMap(ea -> getCertificationActions(ea.getAllTargetsPolicyRules()).stream())
.collect(Collectors.toList());
}
}

private Collection<CertificationPolicyActionType> getCertificationActions(Collection<EvaluatedPolicyRule> policyRules) {
return policyRules.stream()
.filter(r -> !r.getTriggers().isEmpty() && r.getActions() != null && r.getActions().getCertification() != null)
.map(r -> r.getActions().getCertification())
.collect(Collectors.toList());
}

@Override
public void invokeOnException(@NotNull ModelContext context, @NotNull Throwable throwable, @NotNull Task task,
@NotNull OperationResult result) {
// Nothing to do
}

}
Expand Up @@ -47,10 +47,7 @@
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;

import static com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCampaignStateType.*;
import static com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCampaignType.F_CASE;
Expand Down Expand Up @@ -91,10 +88,10 @@ public class CertificationManagerImpl implements CertificationManager {
public static final String INTERFACE_DOT = CertificationManager.class.getName() + ".";
public static final String CLASS_DOT = CertificationManagerImpl.class.getName() + ".";
public static final String OPERATION_CREATE_CAMPAIGN = INTERFACE_DOT + "createCampaign";
public static final String OPERATION_CREATE_AD_HOC_CAMPAIGNS = INTERFACE_DOT + "createAdHocCampaigns";
public static final String OPERATION_OPEN_NEXT_STAGE = INTERFACE_DOT + "openNextStage";
public static final String OPERATION_CLOSE_CURRENT_STAGE = INTERFACE_DOT + "closeCurrentStage";
public static final String OPERATION_RECORD_DECISION = INTERFACE_DOT + "recordDecision";
public static final String OPERATION_SEARCH_DECISIONS = INTERFACE_DOT + "searchOpenWorkItems";
public static final String OPERATION_SEARCH_OPEN_WORK_ITEMS = INTERFACE_DOT + "searchOpenWorkItems";
public static final String OPERATION_CLOSE_CAMPAIGN = INTERFACE_DOT + "closeCampaign";
public static final String OPERATION_DELEGATE_WORK_ITEMS = INTERFACE_DOT + "delegateWorkItems";
Expand Down Expand Up @@ -153,6 +150,63 @@ public AccessCertificationCampaignType createCampaign(String definitionOid, Task
}
}

// This is an action that can be run in unprivileged context. No authorizations are checked. Take care when and where you call it.
// Child result is intentionally created only when a certification campaign is to be started (to avoid useless creation of many empty records)
<O extends ObjectType> void startAdHocCertifications(PrismObject<O> focus,
List<CertificationPolicyActionType> actions, Task task, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException {
Set<String> definitionOids = new HashSet<>();
for (CertificationPolicyActionType action : actions) {
if (action.getDefinitionRef() != null) {
for (ObjectReferenceType definitionRef : action.getDefinitionRef()) {
if (definitionRef.getOid() != null) {
definitionOids.add(definitionRef.getOid());
} else {
// TODO resolve dynamic reference
LOGGER.warn("Certification action having definition reference with no OID; the reference will be ignored: {}", definitionRef);
}
}
} else {
LOGGER.warn("Certification action without definition reference; will be ignored: {}", action);
}
}
if (!definitionOids.isEmpty()) {
OperationResult result = parentResult.createSubresult(OPERATION_CREATE_AD_HOC_CAMPAIGNS);
result.addParam("focus", focus);
result.addCollectionOfSerializablesAsParam("definitionOids", definitionOids);
try {
PrismObject<UserType> administrator = repositoryService
.getObject(UserType.class, SystemObjectsType.USER_ADMINISTRATOR.value(), null, result);
securityEnforcer.runAs(() -> {
for (String definitionOid : definitionOids) {
startAdHocCertification(focus, definitionOid, task, result);
}
parentResult.computeStatus();
return null;
}, administrator);
} catch (RuntimeException e) {
result.recordFatalError(e.getMessage(), e); // TODO
throw e;
}
}
}

private <O extends ObjectType> void startAdHocCertification(PrismObject<O> focus, String definitionOid, Task task,
OperationResult result) {
try {
AccessCertificationDefinitionType definition = repositoryService.getObject(AccessCertificationDefinitionType.class, definitionOid, null, result).asObjectable();
AccessCertificationCampaignType newCampaign = updateHelper.createAdHocCampaignObject(definition, focus, task, result);
updateHelper.addObject(newCampaign, task, result);
openNextStage(newCampaign.getOid(), 1, task, result);
result.computeStatus();
} catch (RuntimeException|SchemaException|ObjectNotFoundException|SecurityViolationException|ObjectAlreadyExistsException e) {
result.recordFatalError("Couldn't create ad-hoc certification campaign: " + e.getMessage(), e);
throw new SystemException("Couldn't create ad-hoc certification campaign: " + e.getMessage(), e);
}
}



@Override
public void openNextStage(String campaignOid, int requestedStageNumber, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ObjectAlreadyExistsException {
Validate.notNull(campaignOid, "campaignOid");
Expand Down

0 comments on commit ab5f5e5

Please sign in to comment.