use of com.evolveum.midpoint.repo.common.expression.Source in project midpoint by Evolveum.
the class LensUtil method formatIterationToken.
public static <F extends ObjectType> String formatIterationToken(LensContext<F> context, LensElementContext<?> accountContext, IterationSpecificationType iterationType, int iteration, ExpressionFactory expressionFactory, ExpressionVariables variables, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException {
if (iterationType == null) {
return formatIterationTokenDefault(iteration);
}
ExpressionType tokenExpressionType = iterationType.getTokenExpression();
if (tokenExpressionType == null) {
return formatIterationTokenDefault(iteration);
}
PrismPropertyDefinition<String> outputDefinition = new PrismPropertyDefinitionImpl<>(ExpressionConstants.VAR_ITERATION_TOKEN, DOMUtil.XSD_STRING, context.getPrismContext());
Expression<PrismPropertyValue<String>, PrismPropertyDefinition<String>> expression = expressionFactory.makeExpression(tokenExpressionType, outputDefinition, "iteration token expression in " + accountContext.getHumanReadableName(), task, result);
Collection<Source<?, ?>> sources = new ArrayList<>();
PrismPropertyDefinitionImpl<Integer> inputDefinition = new PrismPropertyDefinitionImpl<>(ExpressionConstants.VAR_ITERATION, DOMUtil.XSD_INT, context.getPrismContext());
inputDefinition.setMaxOccurs(1);
PrismProperty<Integer> input = inputDefinition.instantiate();
input.add(new PrismPropertyValue<Integer>(iteration));
ItemDeltaItem<PrismPropertyValue<Integer>, PrismPropertyDefinition<Integer>> idi = new ItemDeltaItem<>(input);
Source<PrismPropertyValue<Integer>, PrismPropertyDefinition<Integer>> iterationSource = new Source<>(idi, ExpressionConstants.VAR_ITERATION);
sources.add(iterationSource);
ExpressionEvaluationContext expressionContext = new ExpressionEvaluationContext(sources, variables, "iteration token expression in " + accountContext.getHumanReadableName(), task, result);
PrismValueDeltaSetTriple<PrismPropertyValue<String>> outputTriple = ModelExpressionThreadLocalHolder.evaluateExpressionInContext(expression, expressionContext, task, result);
Collection<PrismPropertyValue<String>> outputValues = outputTriple.getNonNegativeValues();
if (outputValues.isEmpty()) {
return "";
}
if (outputValues.size() > 1) {
throw new ExpressionEvaluationException("Iteration token expression in " + accountContext.getHumanReadableName() + " returned more than one value (" + outputValues.size() + " values)");
}
String realValue = outputValues.iterator().next().getValue();
if (realValue == null) {
return "";
}
return realValue;
}
use of com.evolveum.midpoint.repo.common.expression.Source in project midpoint by Evolveum.
the class ProjectionCredentialsProcessor method processProjectionPasswordMapping.
private <F extends FocusType> void processProjectionPasswordMapping(LensContext<F> context, final LensProjectionContext projCtx, final ValuePolicyType passwordPolicy, XMLGregorianCalendar now, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException {
LensFocusContext<F> focusContext = context.getFocusContext();
PrismObject<F> userNew = focusContext.getObjectNew();
if (userNew == null) {
// This must be a user delete or something similar. No point in proceeding
LOGGER.trace("userNew is null, skipping credentials processing");
return;
}
PrismObjectDefinition<ShadowType> accountDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class);
PrismPropertyDefinition<ProtectedStringType> projPasswordPropertyDefinition = accountDefinition.findPropertyDefinition(SchemaConstants.PATH_PASSWORD_VALUE);
ResourceShadowDiscriminator rsd = projCtx.getResourceShadowDiscriminator();
RefinedObjectClassDefinition refinedProjDef = projCtx.getStructuralObjectClassDefinition();
if (refinedProjDef == null) {
LOGGER.trace("No RefinedObjectClassDefinition, therefore also no password outbound definition, skipping credentials processing for projection {}", rsd);
return;
}
List<MappingType> outboundMappingTypes = refinedProjDef.getPasswordOutbound();
if (outboundMappingTypes == null || outboundMappingTypes.isEmpty()) {
LOGGER.trace("No outbound password mapping for {}, skipping credentials processing", rsd);
return;
}
// HACK
if (!projCtx.isDoReconciliation() && !projCtx.isAdd() && !isActivated(outboundMappingTypes, focusContext.getDelta())) {
LOGGER.trace("Outbound password mappings not activated for type {}, skipping credentials processing", rsd);
return;
}
final ObjectDelta<ShadowType> projDelta = projCtx.getDelta();
final PropertyDelta<ProtectedStringType> projPasswordDelta;
if (projDelta != null && projDelta.getChangeType() == MODIFY) {
projPasswordDelta = projDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE);
} else {
projPasswordDelta = null;
}
checkExistingDeltaSanity(projCtx, projPasswordDelta);
boolean evaluateWeak = getEvaluateWeak(projCtx);
final ItemDeltaItem<PrismPropertyValue<PasswordType>, PrismPropertyDefinition<ProtectedStringType>> userPasswordIdi = focusContext.getObjectDeltaObject().findIdi(SchemaConstants.PATH_PASSWORD_VALUE);
StringPolicyResolver stringPolicyResolver = new StringPolicyResolver() {
@Override
public void setOutputPath(ItemPath outputPath) {
}
@Override
public void setOutputDefinition(ItemDefinition outputDefinition) {
}
@Override
public StringPolicyType resolve() {
if (passwordPolicy == null) {
return null;
}
return passwordPolicy.getStringPolicy();
}
};
MappingInitializer<PrismPropertyValue<ProtectedStringType>, PrismPropertyDefinition<ProtectedStringType>> initializer = (builder) -> {
builder.defaultTargetDefinition(projPasswordPropertyDefinition);
builder.defaultSource(new Source<>(userPasswordIdi, ExpressionConstants.VAR_INPUT));
builder.stringPolicyResolver(stringPolicyResolver);
return builder;
};
MappingOutputProcessor<PrismPropertyValue<ProtectedStringType>> processor = (mappingOutputPath, outputStruct) -> {
PrismValueDeltaSetTriple<PrismPropertyValue<ProtectedStringType>> outputTriple = outputStruct.getOutputTriple();
if (outputTriple == null) {
LOGGER.trace("Credentials 'password' expression resulted in null output triple, skipping credentials processing for {}", rsd);
return false;
}
boolean projectionIsNew = projDelta != null && (projDelta.getChangeType() == ChangeType.ADD || projCtx.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD);
Collection<PrismPropertyValue<ProtectedStringType>> newValues = outputTriple.getPlusSet();
if (projectionIsNew) {
newValues = outputTriple.getNonNegativeValues();
} else {
newValues = outputTriple.getPlusSet();
}
if (!canGetCleartext(newValues)) {
ObjectDelta<ShadowType> projectionPrimaryDelta = projCtx.getPrimaryDelta();
if (projectionPrimaryDelta != null) {
PropertyDelta<ProtectedStringType> passwordPrimaryDelta = projectionPrimaryDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE);
if (passwordPrimaryDelta != null) {
// We have only hashed value coming from the mapping. There are not very useful
// for provisioning. But we have primary projection delta - and that is very likely
// to be better.
// Skip all password mappings in this case. Primary delta trumps everything.
// No weak, normal or even strong mapping can change that.
// We need to disregard even strong mapping in this case. If we would heed the strong
// mapping then account initialization won't be possible.
LOGGER.trace("We have primary password delta in projection, skipping credentials processing");
return false;
}
}
}
return true;
};
mappingEvaluator.evaluateOutboundMapping(context, projCtx, outboundMappingTypes, SchemaConstants.PATH_PASSWORD_VALUE, SchemaConstants.PATH_PASSWORD_VALUE, initializer, processor, now, true, evaluateWeak, "password mapping", task, result);
}
use of com.evolveum.midpoint.repo.common.expression.Source in project midpoint by Evolveum.
the class Mapping method parseSource.
private <IV extends PrismValue, ID extends ItemDefinition> Source<IV, ID> parseSource(VariableBindingDefinitionType sourceType, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException {
ItemPathType itemPathType = sourceType.getPath();
if (itemPathType == null) {
throw new SchemaException("No path in source definition in " + getMappingContextDescription());
}
ItemPath path = itemPathType.getItemPath();
if (path.isEmpty()) {
throw new SchemaException("Empty source path in " + getMappingContextDescription());
}
QName name = sourceType.getName();
if (name == null) {
name = ItemPath.getName(path.last());
}
ItemPath resolvePath = path;
Object sourceObject = ExpressionUtil.resolvePath(path, variables, sourceContext, objectResolver, "source definition in " + getMappingContextDescription(), task, result);
Item<IV, ID> itemOld = null;
ItemDelta<IV, ID> delta = null;
Item<IV, ID> itemNew = null;
ItemPath residualPath = null;
Collection<? extends ItemDelta<?, ?>> subItemDeltas = null;
if (sourceObject != null) {
if (sourceObject instanceof ItemDeltaItem<?, ?>) {
itemOld = ((ItemDeltaItem<IV, ID>) sourceObject).getItemOld();
delta = ((ItemDeltaItem<IV, ID>) sourceObject).getDelta();
itemNew = ((ItemDeltaItem<IV, ID>) sourceObject).getItemNew();
residualPath = ((ItemDeltaItem<IV, ID>) sourceObject).getResidualPath();
resolvePath = ((ItemDeltaItem<IV, ID>) sourceObject).getResolvePath();
subItemDeltas = ((ItemDeltaItem<IV, ID>) sourceObject).getSubItemDeltas();
} else if (sourceObject instanceof Item<?, ?>) {
itemOld = (Item<IV, ID>) sourceObject;
itemNew = (Item<IV, ID>) sourceObject;
} else {
throw new IllegalStateException("Unknown resolve result " + sourceObject);
}
}
// apply domain
ValueSetDefinitionType domainSetType = sourceType.getSet();
if (domainSetType != null) {
ValueSetDefinition setDef = new ValueSetDefinition(domainSetType, name, "domain of " + name.getLocalPart() + " in " + getMappingContextDescription(), task, result);
setDef.init(expressionFactory);
try {
if (itemOld != null) {
itemOld = itemOld.clone();
itemOld.filterValues(val -> setDef.containsTunnel(val));
}
if (itemNew != null) {
itemNew = itemNew.clone();
itemNew.filterValues(val -> setDef.containsTunnel(val));
}
if (delta != null) {
delta = delta.clone();
delta.filterValues(val -> setDef.containsTunnel(val));
}
} catch (TunnelException te) {
Throwable cause = te.getCause();
if (cause instanceof SchemaException) {
throw (SchemaException) cause;
} else if (cause instanceof ExpressionEvaluationException) {
throw (ExpressionEvaluationException) cause;
} else if (cause instanceof ObjectNotFoundException) {
throw (ObjectNotFoundException) cause;
}
}
}
Source<IV, ID> source = new Source<>(itemOld, delta, itemNew, name);
source.setResidualPath(residualPath);
source.setResolvePath(resolvePath);
source.setSubItemDeltas(subItemDeltas);
return source;
}
use of com.evolveum.midpoint.repo.common.expression.Source in project midpoint by Evolveum.
the class InboundProcessor method evaluateInboundMapping.
private <A, F extends FocusType, V extends PrismValue, D extends ItemDefinition> ItemDelta<V, D> evaluateInboundMapping(final LensContext<F> context, MappingType inboundMappingType, QName accountAttributeName, PrismProperty<A> oldAccountProperty, PropertyDelta<A> attributeAPrioriDelta, PrismObject<F> focusNew, PrismObject<ShadowType> account, ResourceType resource, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, ConfigurationException {
if (oldAccountProperty != null && oldAccountProperty.hasRaw()) {
throw new SystemException("Property " + oldAccountProperty + " has raw parsing state, such property cannot be used in inbound expressions");
}
Mapping.Builder<V, D> builder = mappingFactory.createMappingBuilder(inboundMappingType, "inbound expression for " + accountAttributeName + " in " + resource);
if (!builder.isApplicableToChannel(context.getChannel())) {
return null;
}
Source<PrismPropertyValue<A>, PrismPropertyDefinition<A>> defaultSource = new Source<>(oldAccountProperty, attributeAPrioriDelta, null, ExpressionConstants.VAR_INPUT);
defaultSource.recompute();
Mapping<V, D> mapping = builder.defaultSource(defaultSource).targetContext(LensUtil.getFocusDefinition(context)).addVariableDefinition(ExpressionConstants.VAR_USER, focusNew).addVariableDefinition(ExpressionConstants.VAR_FOCUS, focusNew).addVariableDefinition(ExpressionConstants.VAR_ACCOUNT, account).addVariableDefinition(ExpressionConstants.VAR_SHADOW, account).addVariableDefinition(ExpressionConstants.VAR_RESOURCE, resource).stringPolicyResolver(createStringPolicyResolver(context, task, result)).originType(OriginType.INBOUND).originObject(resource).build();
if (checkWeakSkip(mapping, focusNew)) {
LOGGER.trace("Skipping because of mapping is weak and focus property has already a value");
return null;
}
ItemPath targetFocusItemPath = mapping.getOutputPath();
if (ItemPath.isNullOrEmpty(targetFocusItemPath)) {
throw new ConfigurationException("Empty target path in " + mapping.getContextDescription());
}
Item targetFocusItem = null;
if (focusNew != null) {
targetFocusItem = focusNew.findItem(targetFocusItemPath);
}
PrismObjectDefinition<F> focusDefinition = context.getFocusContext().getObjectDefinition();
ItemDefinition targetItemDef = focusDefinition.findItemDefinition(targetFocusItemPath);
if (targetItemDef == null) {
throw new SchemaException("No definition for focus property " + targetFocusItemPath + ", cannot process inbound expression in " + resource);
}
final ItemDelta outputFocusItemDelta = targetItemDef.createEmptyDelta(targetFocusItemPath);
mappingEvaluator.evaluateMapping(mapping, context, task, result);
PrismValueDeltaSetTriple<V> triple = mapping.getOutputTriple();
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Inbound mapping for {} returned triple:\n{}", accountAttributeName, triple == null ? "null" : triple.debugDump());
}
if (triple != null) {
if (triple.hasPlusSet()) {
boolean alreadyReplaced = false;
for (V value : triple.getPlusSet()) {
if (targetFocusItem != null && targetFocusItem.hasRealValue(value)) {
continue;
}
//if property is not multi value replace existing attribute
if (targetFocusItem != null && !targetFocusItem.getDefinition().isMultiValue() && !targetFocusItem.isEmpty()) {
Collection<V> replace = new ArrayList<V>();
replace.add((V) value.clone());
outputFocusItemDelta.setValuesToReplace(replace);
if (alreadyReplaced) {
LOGGER.warn("Multiple values for a single-valued property {}; duplicate value = {}", targetFocusItem, value);
} else {
alreadyReplaced = true;
}
} else {
outputFocusItemDelta.addValueToAdd(value.clone());
}
}
}
if (triple.hasMinusSet()) {
LOGGER.trace("Checking account sync property delta values to delete");
for (V value : triple.getMinusSet()) {
if (targetFocusItem == null || targetFocusItem.hasRealValue(value)) {
if (!outputFocusItemDelta.isReplace()) {
// This is not needed if we are going to replace. In fact it might cause an error.
outputFocusItemDelta.addValueToDelete(value);
}
}
}
}
Item shouldBeItem = targetItemDef.instantiate();
shouldBeItem.addAll(PrismValue.cloneCollection(triple.getZeroSet()));
shouldBeItem.addAll(PrismValue.cloneCollection(triple.getPlusSet()));
if (targetFocusItem != null) {
ItemDelta diffDelta = targetFocusItem.diff(shouldBeItem);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Comparing focus item:\n{}\nto should be item:\n{}\ndiff:\n{} ", DebugUtil.debugDump(targetFocusItem, 1), DebugUtil.debugDump(shouldBeItem, 1), DebugUtil.debugDump(diffDelta, 1));
}
if (diffDelta != null) {
if (mapping.isTolerant() == Boolean.TRUE) {
// this is probably not correct, as the default for inbounds should be TRUE
if (diffDelta.isReplace()) {
if (diffDelta.getValuesToReplace().isEmpty()) {
diffDelta.resetValuesToReplace();
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Removing empty replace part of the diff delta because mapping is tolerant:\n{}", diffDelta.debugDump());
}
} else {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Making sure that the replace part of the diff contains old values delta because mapping is tolerant:\n{}", diffDelta.debugDump());
}
for (Object shouldBeValueObj : shouldBeItem.getValues()) {
PrismValue shouldBeValue = (PrismValue) shouldBeValueObj;
if (!PrismValue.containsRealValue(diffDelta.getValuesToReplace(), shouldBeValue)) {
diffDelta.addValueToReplace(shouldBeValue.clone());
}
}
}
} else {
diffDelta.resetValuesToDelete();
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Removing delete part of the diff delta because mapping is tolerant:\n{}", diffDelta.debugDump());
}
}
}
diffDelta.setElementName(ItemPath.getName(targetFocusItemPath.last()));
diffDelta.setParentPath(targetFocusItemPath.allExceptLast());
outputFocusItemDelta.merge(diffDelta);
}
} else {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Adding user property because inbound say so (account doesn't contain that value):\n{}", shouldBeItem.getValues());
}
//if user property doesn't exist we have to add it (as delta), because inbound say so
outputFocusItemDelta.addValuesToAdd(shouldBeItem.getClonedValues());
}
} else {
// triple == null
// the mapping is not applicable. Nothing to do.
}
// if no changes were generated return null
return outputFocusItemDelta.isEmpty() ? null : outputFocusItemDelta;
}
use of com.evolveum.midpoint.repo.common.expression.Source in project midpoint by Evolveum.
the class TestExpressionProfileSafe method test130Const.
@Test
@Override
public void test130Const() throws Exception {
given();
OperationResult result = createOperationResult();
rememberScriptExecutionCount();
ExpressionType expressionType = parseExpression(EXPRESSION_CONST_FILE);
Collection<Source<?, ?>> sources = prepareStringSources();
VariablesMap variables = prepareBasicVariables();
ExpressionEvaluationContext expressionContext = new ExpressionEvaluationContext(sources, variables, getTestNameShort(), null);
when();
evaluatePropertyExpressionRestricted(expressionType, PrimitiveType.STRING, expressionContext, result);
then();
assertScriptExecutionIncrement(0);
}
Aggregations