/** 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;
 }
示例#6
0
 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;
 }
示例#7
0
 /**
  * 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;
 }
示例#8
0
 /** 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();
 }
示例#10
0
 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);
  }
示例#12
0
 // 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();
  }