Skip to content

Commit

Permalink
forced assignemnts - lifecycle state.. WIP, support in assignemnt eva…
Browse files Browse the repository at this point in the history
…luator + userProfileService...
  • Loading branch information
katkav committed Jul 10, 2018
1 parent c6e42bd commit 537c6f1
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 21 deletions.
Expand Up @@ -15,9 +15,25 @@
*/
package com.evolveum.midpoint.schema.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.marshaller.QueryConvertor;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.schema.ResultHandler;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LifecycleStateModelType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LifecycleStateType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType;
import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType;

/**
* @author semancik
Expand All @@ -39,5 +55,39 @@ public static LifecycleStateType findStateDefinition(LifecycleStateModelType lif
}
return null;
}

public static ObjectFilter getForcedAssignmentFilter(LifecycleStateModelType lifecycleModel, String targetLifecycleState, PrismContext prismContext) throws SchemaException {
LifecycleStateType stateDefinition = findStateDefinition(lifecycleModel, targetLifecycleState);
if (stateDefinition == null) {
return null;
}

SearchFilterType filter = stateDefinition.getForcedAssignment();
if (filter == null) {
return null;
}

ObjectFilter objectFilter = QueryConvertor.parseFilter(filter, RoleType.class, prismContext);
return objectFilter;
}

// public static <T extends AbstractRoleType> Collection<T> getListOfForcedRoles(LifecycleStateModelType lifecycleModel,
// String targetLifecycleState, PrismContext prismContext, ObjectResolver resolver, Task task, OperationResult result) {
// ObjectFilter filter = getForcedAssignmentFilter(lifecycleModel, targetLifecycleState, prismContext);
//
// if (filter == null) {
// return null;
// }
//
// Collection<T> forcedRoles = new HashSet<>();
// ResultHandler<T> handler = (object, parentResult) -> {
// return forcedRoles.add(object.asObjectable());
// };
//
//
// resolver.searchIterative(AbstractRoleType.class,
// ObjectQuery.createObjectQuery(filter), null, handler, task, result);
//
// }

}
Expand Up @@ -2031,14 +2031,18 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<xsd:element name="forcedAssignment" type="tns:ObjectReferenceType">
<xsd:element name="forcedAssignment" type="q:SearchFilterType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Reference to the role, service or org.
<p>
There are cases when you need to force midpoint thinks that user has assigned some
role. The assignemnt actually doesn't exist but there is a need to preted as it does.
This can be used e.g. for post-authentication flow. The user has assigned all business,
application, etc. roles but we don't want to consider these roles during his
post-authentication proces. Instead, we want to pretend he has "temporary" role assigned
which allows him to perform post-authentication.
</p>
</xsd:documentation>
<xsd:appinfo>
<a:objectReferenceTargetType>tns:AbstractRoleType</a:objectReferenceTargetType>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<xsd:element name="activeAssignments" type="xsd:boolean" minOccurs="0">
Expand Down
Expand Up @@ -17,6 +17,7 @@

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
Expand Down Expand Up @@ -48,13 +49,16 @@
import com.evolveum.midpoint.prism.marshaller.QueryConvertor;
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.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.ResultHandler;
import com.evolveum.midpoint.schema.constants.ExpressionConstants;
import com.evolveum.midpoint.schema.constants.ObjectTypes;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.internals.InternalMonitor;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.FocusTypeUtil;
import com.evolveum.midpoint.schema.util.LifecyleUtil;
import com.evolveum.midpoint.schema.util.ObjectResolver;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.security.api.Authorization;
Expand Down Expand Up @@ -325,15 +329,55 @@ private void evaluateFromSegment(AssignmentPathSegmentImpl segment, PlusMinusZer
}
}

boolean isValid = evaluateContent && evaluateSegmentContent(segment, relativeMode, ctx);
boolean isVirtual = isForcedAssignment(segment, ctx);
ctx.evalAssignment.setVirtual(isVirtual);
boolean isValid = (evaluateContent && evaluateSegmentContent(segment, relativeMode, ctx)) || isVirtual;


ctx.assignmentPath.removeLast(segment);
if (ctx.assignmentPath.isEmpty()) { // direct assignment
ctx.evalAssignment.setValid(isValid);
}
}

// "content" means "payload + targets" here

private boolean isForcedAssignment(AssignmentPathSegmentImpl segment, EvaluationContext ctx) {

F focusNew = focusOdo.getNewObject().asObjectable();
Collection<AbstractRoleType> forcedRoles = new HashSet<>();
try {
ObjectFilter filter = LifecyleUtil.getForcedAssignmentFilter(focusStateModel, focusNew.getLifecycleState(), prismContext);
if (filter == null) {
return false;
}

ResultHandler<AbstractRoleType> handler = (object, result) -> {
return forcedRoles.add(object.asObjectable());
};
objectResolver.searchIterative(AbstractRoleType.class, ObjectQuery.createObjectQuery(filter), null, handler, ctx.task, ctx.result);
} catch (SchemaException | ObjectNotFoundException | CommunicationException | ConfigurationException
| SecurityViolationException | ExpressionEvaluationException e) {
LOGGER.error("Cannot search for forced roles", e);
}

for (AbstractRoleType forcedRole : forcedRoles) {
ObjectFilter filterTargetRef = QueryBuilder.queryFor(AssignmentType.class, prismContext)
.item(AssignmentType.F_TARGET_REF).ref(forcedRole.getOid()).buildFilter();
AssignmentType assignmentType = getAssignmentType(segment, ctx);
try {
if (filterTargetRef.match(assignmentType.asPrismContainerValue(), null)) {
return true;
}
} catch (SchemaException e) {
LOGGER.error("Cannot evaluate filter {} for assignemnt {}", filterTargetRef, assignmentType);
continue;
}
}

return false;

}

// "content" means "payload + targets" here
private <O extends ObjectType> boolean evaluateSegmentContent(AssignmentPathSegmentImpl segment,
PlusMinusZero relativeMode, EvaluationContext ctx)
throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, PolicyViolationException, SecurityViolationException, ConfigurationException, CommunicationException {
Expand All @@ -343,7 +387,9 @@ private <O extends ObjectType> boolean evaluateSegmentContent(AssignmentPathSegm
final boolean isDirectAssignment = ctx.assignmentPath.size() == 1;

AssignmentType assignmentType = getAssignmentType(segment, ctx);
boolean isAssignmentValid = LensUtil.isAssignmentValid(focusOdo.getNewObject().asObjectable(), assignmentType, now, activationComputer, focusStateModel);

boolean isAssignmentValid = LensUtil.isAssignmentValid(focusOdo.getNewObject().asObjectable(), assignmentType,
now, activationComputer, focusStateModel);
if (isAssignmentValid || segment.isValidityOverride()) {
// Note: validityOverride is currently the same as "isDirectAssignment" - which is very probably OK.
// Direct assignments are visited even if they are not valid (i.e. effectively disabled).
Expand Down
Expand Up @@ -83,6 +83,7 @@ public class EvaluatedAssignmentImpl<F extends FocusType> implements EvaluatedAs
@NotNull private final Collection<EvaluatedPolicyRule> otherTargetsPolicyRules = new ArrayList<>();

private PrismObject<?> target;
private boolean virtual;
private boolean isValid;
private boolean wasValid;
private boolean forceRecon; // used also to force recomputation of parentOrgRefs
Expand Down Expand Up @@ -284,6 +285,14 @@ public void setTarget(PrismObject<?> target) {
this.target = target;
}

public boolean isVirtual() {
return virtual;
}

public void setVirtual(boolean virtual) {
this.virtual = virtual;
}

/* (non-Javadoc)
* @see com.evolveum.midpoint.model.impl.lens.EvaluatedAssignment#isValid()
*/
Expand Down
Expand Up @@ -19,6 +19,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
Expand All @@ -36,6 +37,10 @@
import com.evolveum.midpoint.model.common.mapping.PrismValueDeltaSetTripleProducer;
import com.evolveum.midpoint.model.impl.util.Utils;
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.RefFilter;
import com.evolveum.midpoint.prism.query.builder.QueryBuilder;
import com.evolveum.midpoint.prism.polystring.AlphanumericPolyStringNormalizer;
import com.evolveum.midpoint.schema.SchemaConstantsGenerated;
import com.evolveum.midpoint.schema.util.*;
Expand All @@ -61,6 +66,7 @@
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.prism.delta.PropertyDelta;
import com.evolveum.midpoint.prism.marshaller.QueryConvertor;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.provisioning.api.ProvisioningService;
import com.evolveum.midpoint.repo.common.expression.Expression;
Expand All @@ -73,6 +79,7 @@
import com.evolveum.midpoint.schema.CapabilityUtil;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.ResourceShadowDiscriminator;
import com.evolveum.midpoint.schema.ResultHandler;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.constants.ExpressionConstants;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
Expand All @@ -81,6 +88,7 @@
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType;
import com.evolveum.prism.xml.ns._public.types_3.PolyStringType;
import org.jetbrains.annotations.NotNull;

Expand Down Expand Up @@ -555,14 +563,37 @@ public static <F extends ObjectType> boolean evaluateIterationCondition(LensCont
/**
* Used for assignments and similar objects that do not have separate lifecycle.
*/
public static boolean isAssignmentValid(FocusType focus, AssignmentType assignmentType, XMLGregorianCalendar now, ActivationComputer activationComputer, LifecycleStateModelType focusStateModel) {
public static boolean isAssignmentValid(FocusType focus, AssignmentType assignmentType, XMLGregorianCalendar now,
ActivationComputer activationComputer, LifecycleStateModelType focusStateModel) {
String focusLifecycleState = focus.getLifecycleState();
if (!activationComputer.lifecycleHasActiveAssignments(focusLifecycleState, focusStateModel)) {

if (!activationComputer.lifecycleHasActiveAssignments(focusLifecycleState, focusStateModel)) {
return false;
}
return isValid(assignmentType.getLifecycleState(), assignmentType.getActivation(), now, activationComputer, focusStateModel);
}


public static Collection<AssignmentType> getForcedAssignments(LifecycleStateModelType lifecycleModel, String targetLifecycle,
ObjectResolver objectResolver, PrismContext prismContext, Task task, OperationResult result) throws SchemaException,
ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException {
ObjectFilter filter = LifecyleUtil.getForcedAssignmentFilter(lifecycleModel, targetLifecycle, prismContext);

Collection<AssignmentType> forcedAssignments = new HashSet<>();
if (filter != null) {

ResultHandler<AbstractRoleType> handler = (object, parentResult) -> {
AssignmentType assignment = ObjectTypeUtil.createAssignmentTo(object);
return forcedAssignments.add(assignment);
};

objectResolver.searchIterative(AbstractRoleType.class,
ObjectQuery.createObjectQuery(filter), null, handler, task, result);

}

return forcedAssignments;
}

public static boolean isFocusValid(FocusType focus, XMLGregorianCalendar now, ActivationComputer activationComputer, LifecycleStateModelType focusStateModel) {
return isValid(focus.getLifecycleState(), focus.getActivation(), now, activationComputer, focusStateModel);
}
Expand Down
Expand Up @@ -49,20 +49,22 @@ public class SmartAssignmentCollection<F extends FocusType> implements Iterable<
private Map<SmartAssignmentKey,SmartAssignmentElement> aMap = null;
private Map<Long,SmartAssignmentElement> idMap;

public void collect(PrismObject<F> objectCurrent, PrismObject<F> objectOld, ContainerDelta<AssignmentType> assignmentDelta) throws SchemaException {
public void collect(PrismObject<F> objectCurrent, PrismObject<F> objectOld, ContainerDelta<AssignmentType> assignmentDelta, Collection<AssignmentType> forcedAssignments) throws SchemaException {
PrismContainer<AssignmentType> assignmentContainerCurrent = null;
if (objectCurrent != null) {
assignmentContainerCurrent = objectCurrent.findContainer(FocusType.F_ASSIGNMENT);
}

if (aMap == null) {
int initialCapacity = computeInitialCapacity(assignmentContainerCurrent, assignmentDelta);
int initialCapacity = computeInitialCapacity(assignmentContainerCurrent, assignmentDelta, forcedAssignments);
aMap = new HashMap<>(initialCapacity);
idMap = new HashMap<>(initialCapacity);
}

collectAssignments(assignmentContainerCurrent, Mode.CURRENT);


collectAssignments(forcedAssignments, Mode.CURRENT);

if (objectOld != null) {
collectAssignments(objectOld.findContainer(FocusType.F_ASSIGNMENT), Mode.OLD);
}
Expand All @@ -78,7 +80,16 @@ private void collectAssignments(PrismContainer<AssignmentType> assignmentContain
collectAssignment(assignmentCVal, mode);
}
}


private void collectAssignments(Collection<AssignmentType> forcedAssignments, Mode mode) throws SchemaException {
if (forcedAssignments == null) {
return;
}
for (AssignmentType assignment : forcedAssignments) {
collectAssignment(assignment.asPrismContainerValue(), mode);
}
}

private void collectAssignments(ContainerDelta<AssignmentType> assignmentDelta) throws SchemaException {
if (assignmentDelta == null) {
return;
Expand Down Expand Up @@ -158,14 +169,18 @@ private SmartAssignmentElement lookup(PrismContainerValue<AssignmentType> assign
return aMap.get(key);
}

private int computeInitialCapacity(PrismContainer<AssignmentType> assignmentContainerCurrent, ContainerDelta<AssignmentType> assignmentDelta) {
private int computeInitialCapacity(PrismContainer<AssignmentType> assignmentContainerCurrent, ContainerDelta<AssignmentType> assignmentDelta, Collection<AssignmentType> forcedAssignments) {
int capacity = 0;
if (assignmentContainerCurrent != null) {
capacity += assignmentContainerCurrent.size();
}
if (assignmentDelta != null) {
capacity += assignmentDelta.size();
}

if (forcedAssignments != null) {
capacity += forcedAssignments.size();
}
return capacity;
}

Expand Down
Expand Up @@ -873,6 +873,9 @@ private <V extends PrismValue, D extends ItemDefinition, F extends FocusType> XM
XMLGregorianCalendar nextRecomputeTime = null;

for (EvaluatedAssignmentImpl<F> ea: evaluatedAssignments) {
if (ea.isVirtual()) {
continue;
}
Collection<MappingImpl<V,D>> focusMappings = (Collection)ea.getFocusMappings();
for (MappingImpl<V,D> mapping: focusMappings) {

Expand Down Expand Up @@ -916,7 +919,7 @@ public <F extends ObjectType> void processMembershipAndDelegatedRefs(LensContext
return; // could be if the "assignments" step is skipped
}
for (EvaluatedAssignmentImpl<?> evalAssignment : evaluatedAssignmentTriple.getNonNegativeValues()) {
if (evalAssignment.isValid()) {
if (evalAssignment.isValid() && !evalAssignment.isVirtual()) {
addReferences(shouldBeRoleRefs, evalAssignment.getMembershipRefVals());
addReferences(shouldBeDelegatedRefs, evalAssignment.getDelegationRefVals());
}
Expand Down

0 comments on commit 537c6f1

Please sign in to comment.