use of com.evolveum.midpoint.xml.ns._public.common.common_3.OrderConstraintsType in project midpoint by Evolveum.
the class ClockworkAuthorizationHelper method authorizeAssignmentRequest.
private <F extends ObjectType, O extends ObjectType> void authorizeAssignmentRequest(LensContext<F> context, String operationUrl, String assignActionUrl, ItemName assignmentElementQName, PrismObject<O> object, OwnerResolver ownerResolver, ObjectSecurityConstraints securityConstraints, PlusMinusZero plusMinusZero, boolean prohibitPolicies, Task task, OperationResult result) throws SecurityViolationException, SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException {
// This is *request* authorization. Therefore we care only about primary delta.
ObjectDelta<F> focusPrimaryDelta = context.getFocusContext().getPrimaryDelta();
if (focusPrimaryDelta == null) {
return;
}
ContainerDelta<AssignmentType> focusAssignmentDelta = focusPrimaryDelta.findContainerDelta(assignmentElementQName);
if (focusAssignmentDelta == null) {
return;
}
String operationDesc = assignActionUrl.substring(assignActionUrl.lastIndexOf('#') + 1);
Collection<PrismContainerValue<AssignmentType>> changedAssignmentValues = determineChangedAssignmentValues(context.getFocusContext(), assignmentElementQName, focusAssignmentDelta, plusMinusZero);
for (PrismContainerValue<AssignmentType> changedAssignmentValue : changedAssignmentValues) {
AssignmentType changedAssignment = changedAssignmentValue.getRealValue();
ObjectReferenceType targetRef = changedAssignment.getTargetRef();
if (targetRef == null || targetRef.getOid() == null) {
// This may still be allowed by #add and #modify authorizations. We have already checked these, but there may be combinations of
// assignments, one of the assignments allowed by #assign, other allowed by #modify (e.g. MID-4517).
// Therefore check the items again. This is not very efficient to check it twice. But this is not a common case
// so there should not be any big harm in suffering this inefficiency.
AccessDecision subitemDecision = securityEnforcer.determineSubitemDecision(securityConstraints, changedAssignmentValue, operationUrl, getRequestAuthorizationPhase(context), null, plusMinusZero, operationDesc);
if (subitemDecision == AccessDecision.ALLOW) {
LOGGER.debug("{} of policy {} to {} allowed with {} authorization", operationDesc, assignmentElementQName.getLocalPart(), object, operationUrl);
continue;
} else {
LOGGER.debug("{} of non-target {} not allowed", operationDesc, assignmentElementQName.getLocalPart());
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Denied request for object {}: {} of non-target {} not allowed", object, operationDesc, assignmentElementQName.getLocalPart());
}
securityEnforcer.failAuthorization(operationDesc, getRequestAuthorizationPhase(context), AuthorizationParameters.Builder.buildObject(object), result);
}
}
PrismObject<ObjectType> target;
try {
// We do not worry about performance here too much. The target was already evaluated. This will be retrieved from repo cache anyway.
target = objectResolver.resolve(targetRef.asReferenceValue(), "resolving " + assignmentElementQName.getLocalPart() + " target", task, result);
} catch (ObjectNotFoundException e) {
LOGGER.warn("Object {} referenced as {} target in {} was not found", targetRef.asReferenceValue().getOid(), assignmentElementQName.getLocalPart(), object);
target = null;
}
ObjectDelta<O> assignmentObjectDelta = object.createModifyDelta();
ContainerDelta<AssignmentType> assignmentDelta = assignmentObjectDelta.createContainerModification(assignmentElementQName);
// We do not care if this is add or delete. All that matters for authorization is that it is in a delta.
assignmentDelta.addValuesToAdd(changedAssignment.asPrismContainerValue().clone());
QName relation = targetRef.getRelation();
if (relation == null) {
relation = prismContext.getDefaultRelation();
}
List<OrderConstraintsType> orderConstraints = determineOrderConstraints(assignmentElementQName, changedAssignment);
AuthorizationParameters<O, ObjectType> autzParams = new AuthorizationParameters.Builder<O, ObjectType>().oldObject(object).delta(assignmentObjectDelta).target(target).relation(relation).orderConstraints(orderConstraints).build();
if (prohibitPolicies) {
if (changedAssignment.getPolicyRule() != null || !changedAssignment.getPolicyException().isEmpty() || !changedAssignment.getPolicySituation().isEmpty() || !changedAssignment.getTriggeredPolicyRule().isEmpty()) {
// This may still be allowed by #add and #modify authorizations. We have already checked these, but there may be combinations of
// assignments, one of the assignments allowed by #assign, other allowed by #modify (e.g. MID-4517).
// Therefore check the items again. This is not very efficient to check it twice. But this is not a common case
// so there should not be any big harm in suffering this inefficiency.
AccessDecision subitemDecision = securityEnforcer.determineSubitemDecision(securityConstraints, changedAssignmentValue, operationUrl, getRequestAuthorizationPhase(context), null, plusMinusZero, operationDesc);
if (subitemDecision == AccessDecision.ALLOW) {
LOGGER.debug("{} of policy assignment to {} allowed with {} authorization", operationDesc, object, operationUrl);
continue;
} else {
securityEnforcer.failAuthorization("with assignment because of policies in the assignment", getRequestAuthorizationPhase(context), autzParams, result);
}
}
}
if (securityEnforcer.isAuthorized(assignActionUrl, getRequestAuthorizationPhase(context), autzParams, ownerResolver, task, result)) {
LOGGER.debug("{} of target {} to {} allowed with {} authorization", operationDesc, target, object, assignActionUrl);
continue;
}
if (relationRegistry.isDelegation(relation)) {
if (securityEnforcer.isAuthorized(ModelAuthorizationAction.DELEGATE.getUrl(), getRequestAuthorizationPhase(context), autzParams, ownerResolver, task, result)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("{} of target {} to {} allowed with {} authorization", operationDesc, target, object, ModelAuthorizationAction.DELEGATE.getUrl());
}
continue;
}
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("{} of target {} to {} denied", operationDesc, target, object);
}
securityEnforcer.failAuthorization("with " + assignmentElementQName.getLocalPart(), getRequestAuthorizationPhase(context), autzParams, result);
}
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.OrderConstraintsType in project midpoint by Evolveum.
the class TargetInducementEvaluation method computeOrderAdjustment.
/**
* Tries to compute correct evaluation order after application of an inducement. Terrible method.
* For some background please see comments at the end of {@link AssignmentPathSegmentImpl} class.
*/
private OrderAdjustment computeOrderAdjustment() {
EvaluationOrder currentOrder = segment.getEvaluationOrder();
EvaluationOrder currentTargetOrder = segment.getEvaluationOrderForTarget();
List<OrderConstraintsType> constraints = new ArrayList<>(inducement.getOrderConstraint());
Integer order = inducement.getOrder();
if (constraints.isEmpty()) {
if (order == null || order == 1) {
return new OrderAdjustment(currentOrder, currentTargetOrder);
} else if (order <= 0) {
throw new IllegalStateException("Wrong inducement order: it must be positive but it is " + order + " instead");
}
// converting legacy -> new specification
int currentSummary = currentOrder.getSummaryOrder();
if (order > currentSummary) {
LOGGER.trace("order of the inducement ({}) is greater than the current evaluation order ({}), marking as undefined", order, currentOrder);
return OrderAdjustment.undefined();
} else {
// i.e. currentOrder >= order, i.e. currentOrder > order-1
int newOrder = currentSummary - (order - 1);
assert newOrder > 0;
constraints.add(new OrderConstraintsType(ctx.ae.prismContext).order(order).resetOrder(newOrder));
}
}
OrderConstraintsType summaryConstraints = getConstraintWithoutRelation(constraints);
Integer resetSummaryTo = summaryConstraints != null && summaryConstraints.getResetOrder() != null ? summaryConstraints.getResetOrder() : null;
OrderAdjustment adjustment;
if (resetSummaryTo != null) {
adjustment = applyResetSummary(currentOrder, currentTargetOrder, constraints, resetSummaryTo);
} else {
adjustment = applyResetForRelations(currentOrder, currentTargetOrder, constraints);
}
if (!adjustment.evaluationOrder.isDefined()) {
return adjustment;
}
if (adjustment.evaluationOrder.getSummaryOrder() <= 0) {
return OrderAdjustment.undefined();
}
if (!adjustment.evaluationOrder.isValid()) {
throw new AssertionError("Resulting evaluation order path is invalid: " + adjustment.evaluationOrder);
}
if (adjustment.targetEvaluationOrder.isValid()) {
return adjustment;
} else {
// some extreme cases like the one described in TestAssignmentProcessor2.test520
return new OrderAdjustment(adjustment.evaluationOrder, EvaluationOrderImpl.UNDEFINED, adjustment.lastEqualOrderSegmentIndex);
}
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.OrderConstraintsType in project midpoint by Evolveum.
the class FocusTypeUtil method dumpInducementConstraints.
public static String dumpInducementConstraints(AssignmentType assignmentType) {
if (assignmentType.getOrder() != null) {
return assignmentType.getOrder().toString();
}
if (assignmentType.getOrderConstraint().isEmpty()) {
return "1";
}
StringBuilder sb = new StringBuilder();
for (OrderConstraintsType orderConstraint : assignmentType.getOrderConstraint()) {
if (orderConstraint.getRelation() != null) {
sb.append(orderConstraint.getRelation().getLocalPart());
} else {
sb.append("null");
}
sb.append(":");
if (orderConstraint.getOrder() != null) {
sb.append(orderConstraint.getOrder());
} else {
sb.append(orderConstraint.getOrderMin());
sb.append("-");
sb.append(orderConstraint.getOrderMax());
}
sb.append(",");
}
sb.setLength(sb.length() - 1);
return sb.toString();
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.OrderConstraintsType in project midpoint by Evolveum.
the class ClockworkAuthorizationHelper method determineOrderConstraints.
private List<OrderConstraintsType> determineOrderConstraints(QName assignmentElementQName, AssignmentType changedAssignment) {
OrderConstraintsType orderConstraints = new OrderConstraintsType();
if (FocusType.F_ASSIGNMENT.equals(assignmentElementQName)) {
orderConstraints.setOrder(0);
} else {
List<OrderConstraintsType> assignmentOrderConstraints = changedAssignment.getOrderConstraint();
if (!assignmentOrderConstraints.isEmpty()) {
return assignmentOrderConstraints;
}
Integer assignmentOrder = changedAssignment.getOrder();
if (assignmentOrder == null) {
orderConstraints.setOrder(1);
} else {
orderConstraints.setOrder(assignmentOrder);
}
}
List<OrderConstraintsType> orderConstraintsList = new ArrayList<>(1);
orderConstraintsList.add(orderConstraints);
return orderConstraintsList;
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.OrderConstraintsType in project midpoint by Evolveum.
the class TargetInducementEvaluation method applyResetSummary.
private OrderAdjustment applyResetSummary(EvaluationOrder currentOrder, EvaluationOrder currentTargetOrder, List<OrderConstraintsType> constraints, Integer resetSummaryTo) {
OrderAdjustment adjustment;
int summaryBackwards = currentOrder.getSummaryOrder() - resetSummaryTo;
if (summaryBackwards < 0) {
// or should we throw an exception?
LOGGER.warn("Cannot move summary order backwards to a negative value ({}). Current order: {}, requested order: {}", summaryBackwards, currentOrder.getSummaryOrder(), resetSummaryTo);
return OrderAdjustment.undefined();
} else if (summaryBackwards > 0) {
int assignmentsSeen = 0;
int i = ctx.assignmentPath.size() - 1;
while (assignmentsSeen < summaryBackwards) {
if (i < 0) {
LOGGER.trace("Cannot move summary order backwards by {}; only {} assignments segment seen: {}", summaryBackwards, assignmentsSeen, ctx.assignmentPath);
return OrderAdjustment.undefined();
}
AssignmentPathSegmentImpl segment = ctx.assignmentPath.getSegments().get(i);
if (segment.isAssignment()) {
if (!ctx.ae.relationRegistry.isDelegation(segment.relation)) {
assignmentsSeen++;
LOGGER.trace("Going back {}: relation at assignment -{} (position -{}): {}", summaryBackwards, assignmentsSeen, ctx.assignmentPath.size() - i, segment.relation);
}
} else {
// for i>0 returns value regardless of evaluateOld
AssignmentType inducement = segment.getAssignment(ctx.evaluateOld);
for (OrderConstraintsType constraint : inducement.getOrderConstraint()) {
if (constraint.getResetOrder() != null && constraint.getRelation() != null) {
LOGGER.debug("Going back {}: an inducement with non-summary resetting constraint found" + " in the chain (at position -{}): {} in {}", summaryBackwards, ctx.assignmentPath.size() - i, constraint, segment);
return OrderAdjustment.undefined();
}
}
if (segment.getLastEqualOrderSegmentIndex() != null) {
i = segment.getLastEqualOrderSegmentIndex();
continue;
}
}
i--;
}
adjustment = new OrderAdjustment(ctx.assignmentPath.getSegments().get(i).getEvaluationOrder(), ctx.assignmentPath.getSegments().get(i).getEvaluationOrderForTarget(), i);
} else {
// summaryBackwards is 0 - nothing to change
adjustment = new OrderAdjustment(currentOrder, currentTargetOrder);
}
if (adjustment.evaluationOrder.isDefined()) {
for (OrderConstraintsType constraint : constraints) {
if (constraint.getRelation() != null && constraint.getResetOrder() != null) {
LOGGER.warn("Ignoring resetOrder (with a value of {} for {}) because summary order was already moved backwards by {} to {}: {}", constraint.getResetOrder(), constraint.getRelation(), summaryBackwards, adjustment.evaluationOrder.getSummaryOrder(), constraint);
}
}
}
return adjustment;
}
Aggregations