Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/Evolveum/midpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
KaterynaHonchar committed Apr 23, 2020
2 parents 35025f7 + a29f86c commit f221661
Show file tree
Hide file tree
Showing 43 changed files with 4,469 additions and 4,474 deletions.
Expand Up @@ -53,7 +53,7 @@ public class ProgressReporter implements ProgressListener {

private Map<String, String> nameCache = new HashMap<>();
private ProgressDto progress = new ProgressDto();
private boolean abortRequested;
private volatile boolean abortRequested;

// Operation result got from the asynchronous operation (null if async op not yet finished)
private OperationResult asyncOperationResult;
Expand Down
Expand Up @@ -54,7 +54,7 @@ public class InternalsConfig {
*/
private static TestingPaths testingPaths = null;

private static boolean detailedAuhotizationLog = false;
private static boolean detailedAuthorizationLog = false;

public static boolean isPrismMonitoring() {
return prismMonitoring;
Expand Down Expand Up @@ -120,12 +120,12 @@ public static void setTestingPaths(TestingPaths testingPaths) {
InternalsConfig.testingPaths = testingPaths;
}

public static boolean isDetailedAuhotizationLog() {
return detailedAuhotizationLog;
public static boolean isDetailedAuthorizationLog() {
return detailedAuthorizationLog;
}

public static void setDetailedAuhotizationLog(boolean detailedAuhotizationLog) {
InternalsConfig.detailedAuhotizationLog = detailedAuhotizationLog;
public static void setDetailedAuthorizationLog(boolean detailedAuthorizationLog) {
InternalsConfig.detailedAuthorizationLog = detailedAuthorizationLog;
}

public static boolean isAllowClearDataLogging() {
Expand Down Expand Up @@ -159,7 +159,7 @@ public static void set(Configuration internalsConfig) {
prismMonitoring = internalsConfig.getBoolean("prismMonitoring", prismMonitoring);
modelProfiling = internalsConfig.getBoolean("modelProfiling", modelProfiling);
// TODO: testingPaths
detailedAuhotizationLog = internalsConfig.getBoolean("detailedAuhotizationLog", detailedAuhotizationLog);
detailedAuthorizationLog = internalsConfig.getBoolean("detailedAuhotizationLog", detailedAuthorizationLog);

}

Expand All @@ -173,7 +173,7 @@ public static void reset() {
prismMonitoring = false;
modelProfiling = false;
testingPaths = null;
detailedAuhotizationLog = false;
detailedAuthorizationLog = false;
}

public static void setDevelopmentMode() {
Expand Down
Expand Up @@ -13,7 +13,7 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;

/**
* Interface used to intercept the SyncContext as it passes through the computation.
* Interface used to intercept the ModelContext as it passes through the computation.
*
* It is mostly used in tests.
*
Expand Down
Expand Up @@ -16,6 +16,11 @@
import java.util.Collection;
import javax.xml.datatype.XMLGregorianCalendar;

import com.evolveum.midpoint.model.impl.lens.projector.Components;

import com.evolveum.midpoint.model.impl.lens.projector.policy.PolicyRuleEnforcer;
import com.evolveum.midpoint.prism.delta.ReferenceDelta;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
Expand Down Expand Up @@ -52,7 +57,6 @@
import com.evolveum.midpoint.schema.cache.CacheConfigurationManager;
import com.evolveum.midpoint.schema.cache.CacheType;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.internals.InternalsConfig;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.result.OperationResultBuilder;
import com.evolveum.midpoint.schema.result.OperationResultStatus;
Expand Down Expand Up @@ -95,6 +99,7 @@ public class Clockwork {
@Autowired private Migrator migrator;
@Autowired private ClockworkMedic medic;
@Autowired private PolicyRuleScriptExecutor policyRuleScriptExecutor;
@Autowired private PolicyRuleEnforcer policyRuleEnforcer;
@Autowired private PolicyRuleSuspendTaskExecutor policyRuleSuspendTaskExecutor;
@Autowired private ClockworkAuthorizationHelper clockworkAuthorizationHelper;
@Autowired private CacheConfigurationManager cacheConfigurationManager;
Expand Down Expand Up @@ -124,9 +129,7 @@ public <F extends ObjectType> HookOperationMode run(LensContext<F> context, Task
}

LOGGER.trace("Running clockwork for context {}", context);
if (InternalsConfig.consistencyChecks) {
context.checkConsistence();
}
context.checkConsistenceIfNeeded();

int clicked = 0;
ClockworkConflictResolver.Context conflictResolutionContext = new ClockworkConflictResolver.Context();
Expand All @@ -141,6 +144,8 @@ public <F extends ObjectType> HookOperationMode run(LensContext<F> context, Task
//enterDefaultSearchExpressionEvaluatorCache();
provisioningService.enterConstraintsCheckerCache();

executeInitialChecks(context);

while (context.getState() != ModelState.FINAL) {

int maxClicks = getMaxClicks(result);
Expand Down Expand Up @@ -191,6 +196,46 @@ public <F extends ObjectType> HookOperationMode run(LensContext<F> context, Task
}
}

private <F extends ObjectType> void executeInitialChecks(LensContext<F> context) throws PolicyViolationException {
if (context.hasFocusOfType(AssignmentHolderType.class)) {
checkArchetypeRefDelta(context);
}
}

/**
* This check was originally present in AssignmentHolderProcessor. But it refers to focus primary delta only;
* so it's sufficient to execute it on clockwork entry (unless primary delta is manipulated e.g. in a scripting hook).
*/
private <F extends ObjectType> void checkArchetypeRefDelta(LensContext<F> context) throws PolicyViolationException {
ObjectDelta<F> focusPrimaryDelta = context.getFocusContext().getPrimaryDelta();
if (focusPrimaryDelta != null) {
ReferenceDelta archetypeRefDelta = focusPrimaryDelta.findReferenceModification(AssignmentHolderType.F_ARCHETYPE_REF);
if (archetypeRefDelta != null) {
// We want to allow this under special circumstances. E.g. we want be able to import user with archetypeRef.
// Otherwise we won't be able to export a user and re-import it again.
if (focusPrimaryDelta.isAdd()) {
String archetypeOidFromAssignments = LensUtil.determineExplicitArchetypeOidFromAssignments(focusPrimaryDelta.getObjectToAdd());
if (archetypeOidFromAssignments == null) {
throw new PolicyViolationException("Attempt add archetypeRef without a matching assignment");
} else {
boolean match = true;
for (PrismReferenceValue archetypeRefDeltaVal : archetypeRefDelta.getValuesToAdd()) {
if (!archetypeOidFromAssignments.equals(archetypeRefDeltaVal.getOid())) {
match = false;
}
}
if (match) {
return;
} else {
throw new PolicyViolationException("Attempt add archetypeRef that does not match assignment");
}
}
}
throw new PolicyViolationException("Attempt to modify archetypeRef directly");
}
}
}

// todo check authorization in this method
private <F extends ObjectType> boolean startTracingIfRequested(LensContext<F> context, Task task,
OperationResultBuilder builder, OperationResult parentResult) throws SchemaException, ObjectNotFoundException,
Expand Down Expand Up @@ -246,6 +291,7 @@ public <F extends ObjectType> LensContext<F> previewChanges(LensContext<F> conte

projector.projectAllWaves(context, "preview", task, result);
clockworkHookHelper.invokePreview(context, task, result);
policyRuleEnforcer.execute(context);
policyRuleSuspendTaskExecutor.execute(context, task, result);

} catch (ConfigurationException | SecurityViolationException | ObjectNotFoundException | SchemaException |
Expand Down Expand Up @@ -365,68 +411,20 @@ public <F extends ObjectType> HookOperationMode click(LensContext<F> context, Ta
context.generateRequestIdentifierIfNeeded();
// We need to do this BEFORE projection. If we would do that after projection
// there will be secondary changes that are not part of the request.
clockworkAuditHelper.audit(context, AuditEventStage.REQUEST, task, result, parentResult); // we need to take the overall ("run" operation result) not the current one
clockworkAuditHelper.audit(context, AuditEventStage.REQUEST, task, result, parentResult); // we need to take the overall ("run" operation result) not the current one
}

boolean recompute = false;
if (!context.isFresh()) {
LOGGER.trace("Context is not fresh -- forcing cleanup and recomputation");
recompute = true;
} else if (context.getExecutionWave() > context.getProjectionWave()) { // should not occur
LOGGER.warn("Execution wave is greater than projection wave -- forcing cleanup and recomputation");
recompute = true;
} else if (state == ModelState.PRIMARY && ModelExecuteOptions.getInitialPartialProcessing(context.getOptions()) != null) {
LOGGER.trace("Initial phase was run with initialPartialProcessing option -- forcing cleanup and recomputation");
recompute = true;
}

if (recompute) {
context.cleanup();
LOGGER.trace("Running projector with cleaned-up context for execution wave {}", context.getExecutionWave());
projector.project(context, "PROJECTOR ("+state+")", task, result);
} else if (context.getExecutionWave() == context.getProjectionWave()) {
LOGGER.trace("Resuming projector for execution wave {}", context.getExecutionWave());
projector.resume(context, "PROJECTOR ("+state+")", task, result);
} else {
LOGGER.trace("Skipping projection because the context is fresh and projection for current wave has already run");
}
projectIfNeeded(context, task, result);

if (!context.isRequestAuthorized()) {
clockworkAuthorizationHelper.authorizeContextRequest(context, task, result);
}

medic.traceContext(LOGGER, "CLOCKWORK (" + state + ")", "before processing", true, context, false);
if (InternalsConfig.consistencyChecks) {
try {
context.checkConsistence();
} catch (IllegalStateException e) {
throw new IllegalStateException(e.getMessage()+" in clockwork, state="+state, e);
}
}
if (InternalsConfig.encryptionChecks && !ModelExecuteOptions.isNoCrypt(context.getOptions())) {
context.checkEncrypted();
}
context.checkConsistenceIfNeeded();
context.checkEncryptedIfNeeded();

switch (state) {
case INITIAL:
processInitialToPrimary(context);
break;
case PRIMARY:
processPrimaryToSecondary(context, task, result);
break;
case SECONDARY:
if (context.getExecutionWave() > context.getMaxWave() + 1) {
processSecondaryToFinal(context, task, result);
} else {
processSecondary(context, task, result, parentResult);
}
break;
case FINAL:
HookOperationMode mode = processFinal(context, task, result, parentResult);
medic.clockworkFinish(context);
return mode;
}
return clockworkHookHelper.invokeHooks(context, task, result);
return moveStateForward(context, task, parentResult, result, state);

} catch (CommunicationException | ConfigurationException | ExpressionEvaluationException | ObjectNotFoundException |
PolicyViolationException | SchemaException | SecurityViolationException | RuntimeException | Error |
Expand All @@ -445,21 +443,76 @@ public <F extends ObjectType> HookOperationMode click(LensContext<F> context, Ta
}
}

private <F extends ObjectType> void projectIfNeeded(LensContext<F> context, Task task, OperationResult result)
throws SchemaException, ConfigurationException, PolicyViolationException, ExpressionEvaluationException,
ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, SecurityViolationException,
PreconditionViolationException {
boolean recompute = false;
if (!context.isFresh()) {
LOGGER.trace("Context is not fresh -- forcing cleanup and recomputation");
recompute = true;
} else if (context.getExecutionWave() > context.getProjectionWave()) { // should not occur
LOGGER.warn("Execution wave is greater than projection wave -- forcing cleanup and recomputation");
recompute = true;
} else if (context.isInPrimary() && ModelExecuteOptions.getInitialPartialProcessing(context.getOptions()) != null) {
LOGGER.trace("Initial phase was run with initialPartialProcessing option -- forcing cleanup and recomputation");
recompute = true;
}

if (recompute) {
context.cleanup();
LOGGER.trace("Running projector with cleaned-up context for execution wave {}", context.getExecutionWave());
projector.project(context, "PROJECTOR ("+ context.getState() +")", task, result);
} else if (context.getExecutionWave() == context.getProjectionWave()) {
LOGGER.trace("Resuming projector for execution wave {}", context.getExecutionWave());
projector.resume(context, "PROJECTOR ("+ context.getState() +")", task, result);
} else {
LOGGER.trace("Skipping projection because the context is fresh and projection for current wave has already run");
}
}

private <F extends ObjectType> HookOperationMode moveStateForward(LensContext<F> context, Task task, OperationResult parentResult,
OperationResult result, ModelState state) throws PolicyViolationException, ObjectNotFoundException, SchemaException,
ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException,
ExpressionEvaluationException, PreconditionViolationException {
switch (state) {
case INITIAL:
processInitialToPrimary(context);
break;
case PRIMARY:
processPrimaryToSecondary(context, task, result);
break;
case SECONDARY:
if (context.getExecutionWave() > context.getMaxWave() + 1) {
processSecondaryToFinal(context, task, result);
} else {
processSecondary(context, task, result, parentResult);
}
break;
case FINAL:
HookOperationMode mode = processFinal(context, task, result, parentResult);
medic.clockworkFinish(context);
return mode;
}
return clockworkHookHelper.invokeHooks(context, task, result);
}

private <F extends ObjectType> void switchState(LensContext<F> context, ModelState newState) {
medic.clockworkStateSwitch(context, newState);
context.setState(newState);
}

private <F extends ObjectType> void processInitialToPrimary(LensContext<F> context) {
// Context loaded, nothing special do. Bump state to PRIMARY.
private <F extends ObjectType> void processInitialToPrimary(LensContext<F> context) throws PolicyViolationException {
// To mimic operation of the original enforcer hook, we execute the following only in the initial state.
policyRuleEnforcer.execute(context);

switchState(context, ModelState.PRIMARY);
}

private <F extends ObjectType> void processPrimaryToSecondary(LensContext<F> context, Task task, OperationResult result) throws PolicyViolationException, ObjectNotFoundException, SchemaException {
// Nothing to do now. The context is already recomputed.
switchState(context, ModelState.SECONDARY);

policyRuleSuspendTaskExecutor.execute(context, task, result);

switchState(context, ModelState.SECONDARY);
}

private <F extends ObjectType> void processSecondary(LensContext<F> context, Task task, OperationResult result, OperationResult overallResult)
Expand All @@ -468,13 +521,13 @@ private <F extends ObjectType> void processSecondary(LensContext<F> context, Tas

Holder<Boolean> restartRequestedHolder = new Holder<>(false);

medic.partialExecute("execution",
medic.partialExecute(Components.EXECUTION,
(result1) -> {
boolean restartRequested = changeExecutor.executeChanges(context, task, result1);
restartRequestedHolder.setValue(restartRequested);
},
context.getPartialProcessingOptions()::getExecution,
Clockwork.class, context, result);
Clockwork.class, context, null, result);

clockworkAuditHelper.audit(context, AuditEventStage.EXECUTION, task, result, overallResult);

Expand Down

0 comments on commit f221661

Please sign in to comment.