/** Adds deltas for iteration and iterationToken to the focus if needed. */ private <F extends FocusType> void addIterationTokenDeltas( LensFocusContext<F> focusContext, int iteration, String iterationToken) throws SchemaException { PrismObject<F> objectCurrent = focusContext.getObjectCurrent(); if (objectCurrent != null) { Integer iterationOld = objectCurrent.asObjectable().getIteration(); String iterationTokenOld = objectCurrent.asObjectable().getIterationToken(); if (iterationOld != null && iterationOld == iteration && iterationTokenOld != null && iterationTokenOld.equals(iterationToken)) { // Already stored return; } } PrismObjectDefinition<F> objDef = focusContext.getObjectDefinition(); PrismPropertyValue<Integer> iterationVal = new PrismPropertyValue<Integer>(iteration); iterationVal.setOriginType(OriginType.USER_POLICY); PropertyDelta<Integer> iterationDelta = PropertyDelta.createReplaceDelta(objDef, FocusType.F_ITERATION, iterationVal); focusContext.swallowToSecondaryDelta(iterationDelta); PrismPropertyValue<String> iterationTokenVal = new PrismPropertyValue<String>(iterationToken); iterationTokenVal.setOriginType(OriginType.USER_POLICY); PropertyDelta<String> iterationTokenDelta = PropertyDelta.createReplaceDelta(objDef, FocusType.F_ITERATION_TOKEN, iterationTokenVal); focusContext.swallowToSecondaryDelta(iterationTokenDelta); }
private <F extends ObjectType> void recordValidityDelta( LensFocusContext<F> focusContext, TimeIntervalStatusType validityStatusNew, XMLGregorianCalendar now) throws SchemaException { PrismContainerDefinition<ActivationType> activationDefinition = getActivationDefinition(); PrismPropertyDefinition<TimeIntervalStatusType> validityStatusDef = activationDefinition.findPropertyDefinition(ActivationType.F_VALIDITY_STATUS); PropertyDelta<TimeIntervalStatusType> validityStatusDelta = validityStatusDef.createEmptyDelta( new ItemPath(UserType.F_ACTIVATION, ActivationType.F_VALIDITY_STATUS)); if (validityStatusNew == null) { validityStatusDelta.setValueToReplace(); } else { validityStatusDelta.setValueToReplace( new PrismPropertyValue<TimeIntervalStatusType>( validityStatusNew, OriginType.USER_POLICY, null)); } focusContext.swallowToProjectionWaveSecondaryDelta(validityStatusDelta); PrismPropertyDefinition<XMLGregorianCalendar> validityChangeTimestampDef = activationDefinition.findPropertyDefinition(ActivationType.F_VALIDITY_CHANGE_TIMESTAMP); PropertyDelta<XMLGregorianCalendar> validityChangeTimestampDelta = validityChangeTimestampDef.createEmptyDelta( new ItemPath(UserType.F_ACTIVATION, ActivationType.F_VALIDITY_CHANGE_TIMESTAMP)); validityChangeTimestampDelta.setValueToReplace( new PrismPropertyValue<XMLGregorianCalendar>(now, OriginType.USER_POLICY, null)); focusContext.swallowToProjectionWaveSecondaryDelta(validityChangeTimestampDelta); }
<F extends ObjectType> void processPasswordPolicy( LensProjectionContext projectionContext, LensContext<F> context, Task task, OperationResult result) throws SchemaException, PolicyViolationException { ObjectDelta accountDelta = projectionContext.getDelta(); if (accountDelta == null) { LOGGER.trace("Skipping processing password policies. Shadow delta not specified."); return; } if (ChangeType.DELETE == accountDelta.getChangeType()) { return; } PrismObject<ShadowType> accountShadow = null; PrismProperty<PasswordType> password = null; if (ChangeType.ADD == accountDelta.getChangeType()) { accountShadow = accountDelta.getObjectToAdd(); if (accountShadow != null) { password = accountShadow.findProperty(SchemaConstants.PATH_PASSWORD_VALUE); } } if (ChangeType.MODIFY == accountDelta.getChangeType() || password == null) { PropertyDelta<PasswordType> passwordValueDelta = null; if (accountDelta != null) { passwordValueDelta = accountDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); // Modification sanity check if (accountDelta.getChangeType() == ChangeType.MODIFY && passwordValueDelta != null && (passwordValueDelta.isAdd() || passwordValueDelta.isDelete())) { throw new SchemaException( "Shadow password value cannot be added or deleted, it can only be replaced"); } if (passwordValueDelta == null) { LOGGER.trace( "Skipping processing password policies. Shadow delta does not contain password change."); return; } password = (PrismProperty<PasswordType>) passwordValueDelta.getItemNewMatchingPath(null); } } // PrismProperty<PasswordType> password = getPassword(projectionContext); ValuePolicyType passwordPolicy = null; if (isCheckOrgPolicy(context)) { passwordPolicy = determineValuePolicy(context.getFocusContext().getObjectAny(), task, result); context.getFocusContext().setOrgPasswordPolicy(passwordPolicy); } else { passwordPolicy = projectionContext.getEffectivePasswordPolicy(); } processPasswordPolicy(passwordPolicy, password, result); }
private PropertyModificationOperation createActivationChange(ActivationStatusType status) { PrismObjectDefinition<ShadowType> shadowDefinition = getShadowDefinition(ShadowType.class); PropertyDelta<ActivationStatusType> delta = PropertyDelta.createDelta( new ItemPath(ShadowType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS), shadowDefinition); delta.setValueToReplace(new PrismPropertyValue<ActivationStatusType>(status)); return new PropertyModificationOperation(delta); }
private PropertyModificationOperation createDeleteAttributeChange( String propertyName, String propertyValue) { PrismProperty property = createProperty(propertyName, propertyValue); ItemPath propertyPath = new ItemPath( ShadowType.F_ATTRIBUTES, new QName(ResourceTypeUtil.getResourceNamespace(resourceType), propertyName)); PropertyDelta delta = new PropertyDelta(propertyPath, property.getDefinition(), prismContext); delta.addValueToDelete(new PrismPropertyValue(propertyValue)); PropertyModificationOperation attributeModification = new PropertyModificationOperation(delta); return attributeModification; }
public static <T> PropertyDelta<T> createModificationDeleteProperty( ItemPath propertyPath, PrismPropertyDefinition propertyDefinition, T... propertyValues) { PropertyDelta<T> propertyDelta = new PropertyDelta<T>( propertyPath, propertyDefinition, propertyDefinition.getPrismContext()); // hoping the prismContext is there Collection<PrismPropertyValue<T>> pValues = new ArrayList<PrismPropertyValue<T>>(propertyValues.length); for (T val : propertyValues) { pValues.add(new PrismPropertyValue<T>(val)); } propertyDelta.addValuesToDelete(pValues); return propertyDelta; }
/** * Convenience method for quick creation of object deltas that replace a single object property. * This is used quite often to justify a separate method. */ public static <T> PropertyDelta<T> createModificationReplaceProperty( ItemPath propertyPath, PrismObjectDefinition<?> objectDefinition, T... propertyValues) { PrismPropertyDefinition propDef = objectDefinition.findPropertyDefinition(propertyPath); PropertyDelta<T> propertyDelta = new PropertyDelta<T>( propertyPath, propDef, objectDefinition.getPrismContext()); // hoping the prismContext is there Collection<PrismPropertyValue<T>> pValues = new ArrayList<PrismPropertyValue<T>>(propertyValues.length); for (T val : propertyValues) { pValues.add(new PrismPropertyValue<T>(val)); } propertyDelta.setValuesToReplace(pValues); return propertyDelta; }
/** Create delta that deletes all values of the specified property. */ public static <O extends Objectable> PropertyDelta createReplaceEmptyDelta( PrismObjectDefinition<O> objectDefinition, QName propertyName) { PrismPropertyDefinition propertyDefinition = objectDefinition.findPropertyDefinition(propertyName); if (propertyDefinition == null) { throw new IllegalArgumentException( "No definition for " + propertyName + " in " + objectDefinition); } PropertyDelta delta = new PropertyDelta( propertyName, propertyDefinition, objectDefinition.getPrismContext()); // hoping the prismContext is there delta.setValuesToReplace(new ArrayList<PrismPropertyValue>()); return delta; }
@Override public String debugDump(int indent) { StringBuilder sb = new StringBuilder(); SchemaDebugUtil.indentDebugDump(sb, indent); sb.append("Property modification operation:\n"); sb.append(propertyDelta.debugDump(indent + 1)); return sb.toString(); }
public static <O extends Objectable> PropertyDelta createDeleteDelta( PrismContainerDefinition<O> containerDefinition, QName propertyName, Object... realValues) { PrismPropertyDefinition propertyDefinition = containerDefinition.findPropertyDefinition(propertyName); if (propertyDefinition == null) { throw new IllegalArgumentException( "No definition for " + propertyName + " in " + containerDefinition); } PropertyDelta delta = new PropertyDelta( propertyName, propertyDefinition, containerDefinition.getPrismContext()); // hoping the prismContext is there for (Object realVal : realValues) { delta.addValueToDelete(new PrismPropertyValue(realVal)); } return delta; }
private <F extends ObjectType> void recordEffectiveStatusDelta( LensFocusContext<F> focusContext, ActivationStatusType effectiveStatusNew, XMLGregorianCalendar now) throws SchemaException { PrismContainerDefinition<ActivationType> activationDefinition = getActivationDefinition(); PrismPropertyDefinition<ActivationStatusType> effectiveStatusDef = activationDefinition.findPropertyDefinition(ActivationType.F_EFFECTIVE_STATUS); PropertyDelta<ActivationStatusType> effectiveStatusDelta = effectiveStatusDef.createEmptyDelta( new ItemPath(UserType.F_ACTIVATION, ActivationType.F_EFFECTIVE_STATUS)); effectiveStatusDelta.setValueToReplace( new PrismPropertyValue<ActivationStatusType>( effectiveStatusNew, OriginType.USER_POLICY, null)); focusContext.swallowToProjectionWaveSecondaryDelta(effectiveStatusDelta); PropertyDelta<XMLGregorianCalendar> timestampDelta = LensUtil.createActivationTimestampDelta( effectiveStatusNew, now, activationDefinition, OriginType.USER_POLICY); focusContext.swallowToProjectionWaveSecondaryDelta(timestampDelta); }
// TODO: the same as createModificationReplaceProperty? // btw, why was here 'PrismObjectDefinition'? public static <O extends Objectable, T> PropertyDelta<T> createReplaceDelta( PrismContainerDefinition<O> containerDefinition, QName propertyName, T... realValues) { PrismPropertyDefinition<T> propertyDefinition = containerDefinition.findPropertyDefinition(propertyName); if (propertyDefinition == null) { throw new IllegalArgumentException( "No definition for " + propertyName + " in " + containerDefinition); } PropertyDelta<T> delta = new PropertyDelta<T>( propertyName, propertyDefinition, containerDefinition.getPrismContext()); // hoping the prismContext is there Collection<PrismPropertyValue<T>> valuesToReplace = delta.getValuesToReplace(); if (valuesToReplace == null) valuesToReplace = new ArrayList<PrismPropertyValue<T>>(realValues.length); for (T realVal : realValues) { valuesToReplace.add(new PrismPropertyValue<T>(realVal)); } delta.setValuesToReplace(valuesToReplace); return delta; }
<F extends FocusType> void processPasswordPolicy( LensFocusContext<F> focusContext, LensContext<F> context, Task task, OperationResult result) throws PolicyViolationException, SchemaException { if (!UserType.class.isAssignableFrom(focusContext.getObjectTypeClass())) { LOGGER.trace("Skipping processing password policies because focus is not user"); return; } // PrismProperty<PasswordType> password = getPassword(focusContext); ObjectDelta userDelta = focusContext.getDelta(); if (userDelta == null) { LOGGER.trace("Skipping processing password policies. User delta not specified."); return; } if (userDelta.isDelete()) { LOGGER.trace("Skipping processing password policies. User will be deleted."); return; } PrismProperty<PasswordType> password = null; PrismObject<F> user; if (ChangeType.ADD == userDelta.getChangeType()) { user = focusContext.getDelta().getObjectToAdd(); if (user != null) { password = user.findProperty(SchemaConstants.PATH_PASSWORD_VALUE); } if (password == null) { if (wasExecuted(userDelta, focusContext)) { LOGGER.trace( "Skipping processing password policies. User addition was already executed."); return; } } } else if (ChangeType.MODIFY == userDelta.getChangeType()) { PropertyDelta<PasswordType> passwordValueDelta; if (userDelta != null) { passwordValueDelta = userDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); if (passwordValueDelta == null) { LOGGER.trace( "Skipping processing password policies. User delta does not contain password change."); return; } if (userDelta.getChangeType() == ChangeType.MODIFY && passwordValueDelta != null) { if (passwordValueDelta.isAdd()) { password = (PrismProperty<PasswordType>) passwordValueDelta.getItemNewMatchingPath(null); } else if (passwordValueDelta.isDelete()) { password = null; } else { password = (PrismProperty<PasswordType>) passwordValueDelta.getItemNewMatchingPath(null); } } else { password = (PrismProperty<PasswordType>) passwordValueDelta.getItemNewMatchingPath(null); } } } ValuePolicyType passwordPolicy; if (focusContext.getOrgPasswordPolicy() == null) { passwordPolicy = determineValuePolicy(userDelta, focusContext.getObjectAny(), context, task, result); focusContext.setOrgPasswordPolicy(passwordPolicy); } else { passwordPolicy = focusContext.getOrgPasswordPolicy(); } processPasswordPolicy(passwordPolicy, password, result); }
private <F extends FocusType> void processFocusFocus( LensContext<F> context, String activityDescription, XMLGregorianCalendar now, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException, PolicyViolationException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { LensFocusContext<F> focusContext = context.getFocusContext(); ObjectTemplateType objectTemplate = context.getFocusTemplate(); boolean resetOnRename = true; // This is fixed now. TODO: make it configurable int maxIterations = 0; IterationSpecificationType iterationSpecificationType = null; if (objectTemplate != null) { iterationSpecificationType = objectTemplate.getIteration(); maxIterations = LensUtil.determineMaxIterations(iterationSpecificationType); } int iteration = focusContext.getIteration(); String iterationToken = focusContext.getIterationToken(); boolean wasResetIterationCounter = false; PrismObject<F> focusCurrent = focusContext.getObjectCurrent(); if (focusCurrent != null && iterationToken == null) { Integer focusIteration = focusCurrent.asObjectable().getIteration(); if (focusIteration != null) { iteration = focusIteration; } iterationToken = focusCurrent.asObjectable().getIterationToken(); } while (true) { ObjectTypeTemplateType objectPolicyConfigurationType = focusContext.getObjectPolicyConfigurationType(); if (objectPolicyConfigurationType != null && BooleanUtils.isTrue(objectPolicyConfigurationType.isOidNameBoundMode())) { // Generate the name now - unless it is already present PrismObject<F> focusNew = focusContext.getObjectNew(); if (focusNew != null) { PolyStringType focusNewName = focusNew.asObjectable().getName(); if (focusNewName == null) { String newName = focusNew.getOid(); if (newName == null) { newName = OidUtil.generateOid(); } LOGGER.trace("Generating new name (bound to OID): {}", newName); PrismObjectDefinition<F> focusDefinition = focusContext.getObjectDefinition(); PrismPropertyDefinition<PolyString> focusNameDef = focusDefinition.findPropertyDefinition(FocusType.F_NAME); PropertyDelta<PolyString> nameDelta = focusNameDef.createEmptyDelta(new ItemPath(FocusType.F_NAME)); nameDelta.setValueToReplace( new PrismPropertyValue<PolyString>( new PolyString(newName), OriginType.USER_POLICY, null)); focusContext.swallowToSecondaryDelta(nameDelta); focusContext.recompute(); } } } ExpressionVariables variables = Utils.getDefaultExpressionVariables( focusContext.getObjectNew(), null, null, null, context.getSystemConfiguration()); if (iterationToken == null) { iterationToken = LensUtil.formatIterationToken( context, focusContext, iterationSpecificationType, iteration, expressionFactory, variables, task, result); } // We have to remember the token and iteration in the context. // The context can be recomputed several times. But we always want // to use the same iterationToken if possible. If there is a random // part in the iterationToken expression that we need to avoid recomputing // the token otherwise the value can change all the time (even for the same inputs). // Storing the token in the secondary delta is not enough because secondary deltas can be // dropped // if the context is re-projected. focusContext.setIteration(iteration); focusContext.setIterationToken(iterationToken); LOGGER.trace( "Focus {} processing, iteration {}, token '{}'", new Object[] {focusContext.getHumanReadableName(), iteration, iterationToken}); String conflictMessage; if (!LensUtil.evaluateIterationCondition( context, focusContext, iterationSpecificationType, iteration, iterationToken, true, expressionFactory, variables, task, result)) { conflictMessage = "pre-iteration condition was false"; LOGGER.debug( "Skipping iteration {}, token '{}' for {} because the pre-iteration condition was false", new Object[] {iteration, iterationToken, focusContext.getHumanReadableName()}); } else { // INBOUND if (consistencyChecks) context.checkConsistence(); // Loop through the account changes, apply inbound expressions inboundProcessor.processInbound(context, now, task, result); if (consistencyChecks) context.checkConsistence(); context.recomputeFocus(); LensUtil.traceContext(LOGGER, activityDescription, "inbound", false, context, false); if (consistencyChecks) context.checkConsistence(); // ACTIVATION processActivation(context, now, result); // OBJECT TEMPLATE (before assignments) objectTemplateProcessor.processTemplate( context, ObjectTemplateMappingEvaluationPhaseType.BEFORE_ASSIGNMENTS, now, task, result); // ASSIGNMENTS assignmentProcessor.processAssignmentsProjections(context, now, task, result); assignmentProcessor.processOrgAssignments(context, result); context.recompute(); assignmentProcessor.checkForAssignmentConflicts(context, result); // OBJECT TEMPLATE (after assignments) objectTemplateProcessor.processTemplate( context, ObjectTemplateMappingEvaluationPhaseType.AFTER_ASSIGNMENTS, now, task, result); context.recompute(); // PASSWORD POLICY passwordPolicyProcessor.processPasswordPolicy(focusContext, context, result); // Processing done, check for success if (resetOnRename && !wasResetIterationCounter && willResetIterationCounter(focusContext)) { // Make sure this happens only the very first time during the first recompute. // Otherwise it will always change the token (especially if the token expression has a // random part) // hence the focusContext.getIterationToken() == null wasResetIterationCounter = true; if (iteration != 0) { iteration = 0; iterationToken = null; LOGGER.trace("Resetting iteration counter and token because rename was detected"); cleanupContext(focusContext); continue; } } PrismObject<F> previewObjectNew = focusContext.getObjectNew(); if (previewObjectNew == null) { // this must be delete } else { // Explicitly check for name. The checker would check for this also. But checking it here // will produce better error message PolyStringType objectName = previewObjectNew.asObjectable().getName(); if (objectName == null || objectName.getOrig().isEmpty()) { throw new SchemaException( "No name in new object " + objectName + " as produced by template " + objectTemplate + " in iteration " + iteration + ", we cannot process an object without a name"); } } // Check if iteration constraints are OK FocusConstraintsChecker<F> checker = new FocusConstraintsChecker<>(); checker.setPrismContext(prismContext); checker.setContext(context); checker.setRepositoryService(cacheRepositoryService); checker.check(previewObjectNew, result); if (checker.isSatisfiesConstraints()) { LOGGER.trace( "Current focus satisfies uniqueness constraints. Iteration {}, token '{}'", iteration, iterationToken); if (LensUtil.evaluateIterationCondition( context, focusContext, iterationSpecificationType, iteration, iterationToken, false, expressionFactory, variables, task, result)) { // stop the iterations break; } else { conflictMessage = "post-iteration condition was false"; LOGGER.debug( "Skipping iteration {}, token '{}' for {} because the post-iteration condition was false", new Object[] {iteration, iterationToken, focusContext.getHumanReadableName()}); } } else { LOGGER.trace( "Current focus does not satisfy constraints. Conflicting object: {}; iteration={}, maxIterations={}", new Object[] {checker.getConflictingObject(), iteration, maxIterations}); conflictMessage = checker.getMessages(); } if (!wasResetIterationCounter) { wasResetIterationCounter = true; if (iteration != 0) { iterationToken = null; iteration = 0; LOGGER.trace("Resetting iteration counter and token after conflict"); cleanupContext(focusContext); continue; } } } // Next iteration iteration++; iterationToken = null; if (iteration > maxIterations) { StringBuilder sb = new StringBuilder(); if (iteration == 1) { sb.append("Error processing "); } else { sb.append("Too many iterations (" + iteration + ") for "); } sb.append(focusContext.getHumanReadableName()); if (iteration == 1) { sb.append(": constraint violation: "); } else { sb.append(": cannot determine values that satisfy constraints: "); } if (conflictMessage != null) { sb.append(conflictMessage); } throw new ObjectAlreadyExistsException(sb.toString()); } cleanupContext(focusContext); } addIterationTokenDeltas(focusContext, iteration, iterationToken); if (consistencyChecks) context.checkConsistence(); }