/* * Copyright (c) 2010-2017 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.evolveum.midpoint.model.impl.expr; import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition; import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.common.refinery.RefinedResourceSchema; import com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl; import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.api.ModelService; import com.evolveum.midpoint.model.api.WorkflowService; import com.evolveum.midpoint.model.api.context.ModelContext; import com.evolveum.midpoint.model.api.context.ModelElementContext; import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision; import com.evolveum.midpoint.model.api.expr.MidpointFunctions; import com.evolveum.midpoint.model.common.expression.script.ScriptExpressionEvaluationContext; import com.evolveum.midpoint.model.impl.ModelObjectResolver; import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.model.impl.lens.LensFocusContext; import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; import com.evolveum.midpoint.model.impl.lens.SynchronizationIntent; import com.evolveum.midpoint.notifications.api.events.ModelEvent; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.crypto.EncryptionException; import com.evolveum.midpoint.prism.crypto.Protector; import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.marshaller.XPathHolder; import com.evolveum.midpoint.prism.match.DefaultMatchingRule; import com.evolveum.midpoint.prism.match.PolyStringOrigMatchingRule; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.query.builder.QueryBuilder; import com.evolveum.midpoint.provisioning.api.ProvisioningService; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.*; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.schema.util.*; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.security.api.SecurityEnforcer; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.Holder; import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CredentialsCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.PasswordCapabilityType; import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; import org.apache.commons.lang.Validate; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import javax.xml.namespace.QName; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.Characters; import javax.xml.stream.events.EndElement; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; /** * @author semancik * */ @Component public class MidpointFunctionsImpl implements MidpointFunctions { private static final Trace LOGGER = TraceManager.getTrace(MidpointFunctionsImpl.class); @Autowired private PrismContext prismContext; @Autowired private ModelService modelService; @Autowired private ModelObjectResolver modelObjectResolver; @Autowired @Qualifier("cacheRepositoryService") private RepositoryService repositoryService; @Autowired private ProvisioningService provisioningService; @Autowired private SecurityEnforcer securityEnforcer; @Autowired private transient Protector protector; @Autowired private OrgStructFunctionsImpl orgStructFunctions; @Autowired private WorkflowService workflowService; public String hello(String name) { return "Hello "+name; } public PrismContext getPrismContext() { return prismContext; } @Override public List<String> toList(String... s) { return Arrays.asList(s); } @Override public UserType getUserByOid(String oid) throws ObjectNotFoundException, SchemaException { return repositoryService.getObject(UserType.class, oid, null, new OperationResult("getUserByOid")).asObjectable(); } @Override public boolean isMemberOf(UserType user, String orgOid) { for (ObjectReferenceType objectReferenceType : user.getParentOrgRef()) { if (orgOid.equals(objectReferenceType.getOid())) { return true; } } return false; } @Override public String getPlaintextUserPassword(UserType user) throws EncryptionException { if (user == null || user.getCredentials() == null || user.getCredentials().getPassword() == null) { return null; // todo log a warning here? } ProtectedStringType protectedStringType = user.getCredentials().getPassword().getValue(); if (protectedStringType != null) { return protector.decryptString(protectedStringType); } else { return null; } } @Override public String getPlaintextAccountPassword(ShadowType account) throws EncryptionException { if (account == null || account.getCredentials() == null || account.getCredentials().getPassword() == null) { return null; // todo log a warning here? } ProtectedStringType protectedStringType = account.getCredentials().getPassword().getValue(); if (protectedStringType != null) { return protector.decryptString(protectedStringType); } else { return null; } } @Override public String getPlaintextAccountPasswordFromDelta(ObjectDelta<? extends ShadowType> delta) throws EncryptionException { if (delta.isAdd()) { ShadowType newShadow = delta.getObjectToAdd().asObjectable(); return getPlaintextAccountPassword(newShadow); } if (!delta.isModify()) { return null; } List<ProtectedStringType> passwords = new ArrayList<ProtectedStringType>(); for (ItemDelta itemDelta : delta.getModifications()) { takePasswordsFromItemDelta(passwords, itemDelta); } LOGGER.trace("Found " + passwords.size() + " password change value(s)"); if (!passwords.isEmpty()) { return protector.decryptString(passwords.get(passwords.size()-1)); } else { return null; } } private void takePasswordsFromItemDelta(List<ProtectedStringType> passwords, ItemDelta itemDelta) { if (itemDelta.isDelete()) { return; } if (itemDelta.getPath().equivalent(new ItemPath(ShadowType.F_CREDENTIALS, CredentialsType.F_PASSWORD, PasswordType.F_VALUE))) { LOGGER.trace("Found password value add/modify delta"); Collection<PrismPropertyValue<ProtectedStringType>> values = itemDelta.isAdd() ? itemDelta.getValuesToAdd() : itemDelta.getValuesToReplace(); for (PrismPropertyValue<ProtectedStringType> value : values) { passwords.add(value.getValue()); } } else if (itemDelta.getPath().equivalent(new ItemPath(ShadowType.F_CREDENTIALS, CredentialsType.F_PASSWORD))) { LOGGER.trace("Found password add/modify delta"); Collection<PrismContainerValue<PasswordType>> values = itemDelta.isAdd() ? itemDelta.getValuesToAdd() : itemDelta.getValuesToReplace(); for (PrismContainerValue<PasswordType> value : values) { if (value.asContainerable().getValue() != null) { passwords.add(value.asContainerable().getValue()); } } } else if (itemDelta.getPath().equivalent(new ItemPath(ShadowType.F_CREDENTIALS))) { LOGGER.trace("Found credentials add/modify delta"); Collection<PrismContainerValue<CredentialsType>> values = itemDelta.isAdd() ? itemDelta.getValuesToAdd() : itemDelta.getValuesToReplace(); for (PrismContainerValue<CredentialsType> value : values) { if (value.asContainerable().getPassword() != null && value.asContainerable().getPassword().getValue() != null) { passwords.add(value.asContainerable().getPassword().getValue()); } } } } @Override public String getPlaintextUserPasswordFromDeltas(List<ObjectDelta<UserType>> objectDeltas) throws EncryptionException { List<ProtectedStringType> passwords = new ArrayList<ProtectedStringType>(); for (ObjectDelta<UserType> delta : objectDeltas) { if (delta.isAdd()) { UserType newUser = delta.getObjectToAdd().asObjectable(); return getPlaintextUserPassword(newUser); // for simplicity we do not look for other values } if (!delta.isModify()) { continue; } for (ItemDelta itemDelta : delta.getModifications()) { takePasswordsFromItemDelta(passwords, itemDelta); } } LOGGER.trace("Found " + passwords.size() + " password change value(s)"); if (!passwords.isEmpty()) { return protector.decryptString(passwords.get(passwords.size()-1)); } else { return null; } } public <F extends ObjectType> boolean hasLinkedAccount(String resourceOid) { LensContext<F> ctx = ModelExpressionThreadLocalHolder.getLensContext(); if (ctx == null) { throw new IllegalStateException("No lens context"); } LensFocusContext<F> focusContext = ctx.getFocusContext(); if (focusContext == null) { throw new IllegalStateException("No focus in lens context"); } ScriptExpressionEvaluationContext scriptContext = ScriptExpressionEvaluationContext.getThreadLocal(); ResourceShadowDiscriminator rat = new ResourceShadowDiscriminator(resourceOid, ShadowKindType.ACCOUNT, null); LensProjectionContext projectionContext = ctx.findProjectionContext(rat); if (projectionContext == null) { // but check if it is not among list of deleted contexts if (scriptContext == null || scriptContext.isEvaluateNew()) { return false; } // evaluating old state for (ResourceShadowDiscriminator deletedOne: ctx.getHistoricResourceObjects()) { if (resourceOid.equals(deletedOne.getResourceOid()) && deletedOne.getKind() == ShadowKindType.ACCOUNT && deletedOne.getIntent() == null || "default".equals(deletedOne.getIntent())) { // TODO implement this seriously LOGGER.trace("Found deleted one: {}", deletedOne); // TODO remove return true; } } return false; } if (projectionContext.isThombstone()) { return false; } SynchronizationPolicyDecision synchronizationPolicyDecision = projectionContext.getSynchronizationPolicyDecision(); SynchronizationIntent synchronizationIntent = projectionContext.getSynchronizationIntent(); if (scriptContext == null) { if (synchronizationPolicyDecision == null) { if (synchronizationIntent == SynchronizationIntent.DELETE || synchronizationIntent == SynchronizationIntent.UNLINK) { return false; } else { return true; } } else { if (synchronizationPolicyDecision == SynchronizationPolicyDecision.DELETE || synchronizationPolicyDecision == SynchronizationPolicyDecision.UNLINK) { return false; } else { return true; } } } else if (scriptContext.isEvaluateNew()) { // Evaluating new state if (focusContext.isDelete()) { return false; } if (synchronizationPolicyDecision == null) { if (synchronizationIntent == SynchronizationIntent.DELETE || synchronizationIntent == SynchronizationIntent.UNLINK) { return false; } else { return true; } } else { if (synchronizationPolicyDecision == SynchronizationPolicyDecision.DELETE || synchronizationPolicyDecision == SynchronizationPolicyDecision.UNLINK) { return false; } else { return true; } } } else { // Evaluating old state if (focusContext.isAdd()) { return false; } if (synchronizationPolicyDecision == null) { if (synchronizationIntent == SynchronizationIntent.ADD) { return false; } else { return true; } } else { if (synchronizationPolicyDecision == SynchronizationPolicyDecision.ADD) { return false; } else { return true; } } } } @Override public <F extends FocusType> boolean isDirectlyAssigned(F focusType, String targetOid) { for (AssignmentType assignment: focusType.getAssignment()) { ObjectReferenceType targetRef = assignment.getTargetRef(); if (targetRef != null && targetRef.getOid().equals(targetOid)) { return true; } } return false; } @Override public <F extends FocusType> boolean isDirectlyAssigned(F focusType, ObjectType target) { return isDirectlyAssigned(focusType, target.getOid()); } @Override public boolean isDirectlyAssigned(String targetOid) { LensContext<? extends FocusType> ctx = ModelExpressionThreadLocalHolder.getLensContext(); if (ctx == null) { throw new IllegalStateException("No lens context"); } LensFocusContext<? extends FocusType> focusContext = ctx.getFocusContext(); if (focusContext == null) { throw new IllegalStateException("No focus in lens context"); } PrismObject<? extends FocusType> focus; ScriptExpressionEvaluationContext scriptContext = ScriptExpressionEvaluationContext.getThreadLocal(); if (scriptContext == null) { focus = focusContext.getObjectAny(); } else if (scriptContext.isEvaluateNew()) { // Evaluating new state if (focusContext.isDelete()) { return false; } focus = focusContext.getObjectNew(); } else { // Evaluating old state if (focusContext.isAdd()) { return false; } focus = focusContext.getObjectOld(); } if (focus == null) { return false; } return isDirectlyAssigned(focus.asObjectable(), targetOid); } @Override public boolean isDirectlyAssigned(ObjectType target) { return isDirectlyAssigned(target.getOid()); } @Override public ShadowType getLinkedShadow(FocusType focus, ResourceType resource) throws SchemaException, SecurityViolationException, CommunicationException, ConfigurationException { return getLinkedShadow(focus, resource.getOid()); } @Override public ShadowType getLinkedShadow(FocusType focus, ResourceType resource, boolean repositoryObjectOnly) throws SchemaException, SecurityViolationException, CommunicationException, ConfigurationException { return getLinkedShadow(focus, resource.getOid(), repositoryObjectOnly); } @Override public ShadowType getLinkedShadow(FocusType focus, String resourceOid) throws SchemaException, SecurityViolationException, CommunicationException, ConfigurationException { return getLinkedShadow(focus, resourceOid, false); } @Override public ShadowType getLinkedShadow(FocusType focus, String resourceOid, boolean repositoryObjectOnly) throws SchemaException, SecurityViolationException, CommunicationException, ConfigurationException { if (focus == null) { return null; } List<ObjectReferenceType> linkRefs = focus.getLinkRef(); for (ObjectReferenceType linkRef: linkRefs) { ShadowType shadowType; try { shadowType = getObject(ShadowType.class, linkRef.getOid(), SelectorOptions.createCollection(GetOperationOptions.createNoFetch())); } catch (ObjectNotFoundException e) { // Shadow is gone in the meantime. MidPoint will resolve that by itself. // It is safe to ignore this error in this method. LOGGER.trace("Ignoring shadow "+linkRef.getOid()+" linked in "+focus+" because it no longer exists in repository"); continue; } if (shadowType.getResourceRef().getOid().equals(resourceOid)) { // We have repo shadow here. Re-read resource shadow if necessary. if (!repositoryObjectOnly) { try { shadowType = getObject(ShadowType.class, shadowType.getOid()); } catch (ObjectNotFoundException e) { // Shadow is gone in the meantime. MidPoint will resolve that by itself. // It is safe to ignore this error in this method. LOGGER.trace("Ignoring shadow "+linkRef.getOid()+" linked in "+focus+" because it no longer exists on resource"); continue; } } return shadowType; } } return null; } @Override public ShadowType getLinkedShadow(FocusType focus, String resourceOid, ShadowKindType kind, String intent) throws SchemaException, SecurityViolationException, CommunicationException, ConfigurationException { return getLinkedShadow(focus, resourceOid, kind, intent, false); } @Override public ShadowType getLinkedShadow(FocusType focus, String resourceOid, ShadowKindType kind, String intent, boolean repositoryObjectOnly) throws SchemaException, SecurityViolationException, CommunicationException, ConfigurationException { List<ObjectReferenceType> linkRefs = focus.getLinkRef(); for (ObjectReferenceType linkRef: linkRefs) { ShadowType shadowType; try { shadowType = getObject(ShadowType.class, linkRef.getOid(), SelectorOptions.createCollection(GetOperationOptions.createNoFetch())); } catch (ObjectNotFoundException e) { // Shadow is gone in the meantime. MidPoint will resolve that by itself. // It is safe to ignore this error in this method. LOGGER.trace("Ignoring shadow "+linkRef.getOid()+" linked in "+focus+" because it no longer exists in repository"); continue; } if (ShadowUtil.matches(shadowType, resourceOid, kind, intent)) { // We have repo shadow here. Re-read resource shadow if necessary. if (!repositoryObjectOnly) { try { shadowType = getObject(ShadowType.class, shadowType.getOid()); } catch (ObjectNotFoundException e) { // Shadow is gone in the meantime. MidPoint will resolve that by itself. // It is safe to ignore this error in this method. LOGGER.trace("Ignoring shadow "+linkRef.getOid()+" linked in "+focus+" because it no longer exists on resource"); continue; } } return shadowType; } } return null; } @Override public boolean isFullShadow() { LensProjectionContext projectionContext = getProjectionContext(); if (projectionContext == null) { LOGGER.debug("Call to isFullShadow while there is no projection context"); return false; } return projectionContext.isFullShadow(); } public <T> Integer countAccounts(String resourceOid, QName attributeName, T attributeValue) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { OperationResult result = getCurrentResult(MidpointFunctions.class.getName()+".countAccounts"); ResourceType resourceType = modelObjectResolver.getObjectSimple(ResourceType.class, resourceOid, null, null, result); return countAccounts(resourceType, attributeName, attributeValue, getCurrentTask(), result); } public <T> Integer countAccounts(ResourceType resourceType, QName attributeName, T attributeValue) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { OperationResult result = getCurrentResult(MidpointFunctions.class.getName()+".countAccounts"); return countAccounts(resourceType, attributeName, attributeValue, getCurrentTask(), result); } public <T> Integer countAccounts(ResourceType resourceType, String attributeName, T attributeValue) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { OperationResult result = getCurrentResult(MidpointFunctions.class.getName()+".countAccounts"); QName attributeQName = new QName(ResourceTypeUtil.getResourceNamespace(resourceType), attributeName); return countAccounts(resourceType, attributeQName, attributeValue, getCurrentTask(), result); } private <T> Integer countAccounts(ResourceType resourceType, QName attributeName, T attributeValue, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { RefinedResourceSchema rSchema = RefinedResourceSchemaImpl.getRefinedSchema(resourceType); RefinedObjectClassDefinition rAccountDef = rSchema.getDefaultRefinedDefinition(ShadowKindType.ACCOUNT); RefinedAttributeDefinition attrDef = rAccountDef.findAttributeDefinition(attributeName); ObjectQuery query = QueryBuilder.queryFor(ShadowType.class, prismContext) .itemWithDef(attrDef, ShadowType.F_ATTRIBUTES, attrDef.getName()).eq(attributeValue) .and().item(ShadowType.F_OBJECT_CLASS).eq(rAccountDef.getObjectClassDefinition().getTypeName()) .and().item(ShadowType.F_RESOURCE_REF).ref(resourceType.getOid()) .build(); return modelObjectResolver.countObjects(ShadowType.class, query, null, task, result); } public <T> boolean isUniquePropertyValue(ObjectType objectType, String propertyPathString, T propertyValue) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { Validate.notEmpty(propertyPathString, "Empty property path"); OperationResult result = getCurrentResult(MidpointFunctions.class.getName()+".isUniquePropertyValue"); ItemPath propertyPath = new XPathHolder(propertyPathString).toItemPath(); return isUniquePropertyValue(objectType, propertyPath, propertyValue, getCurrentTask(), result); } private <T> boolean isUniquePropertyValue(final ObjectType objectType, ItemPath propertyPath, T propertyValue, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { List<? extends ObjectType> conflictingObjects = getObjectsInConflictOnPropertyValue(objectType, propertyPath, propertyValue, null, false, task, result); return conflictingObjects.isEmpty(); } public <O extends ObjectType, T> List<O> getObjectsInConflictOnPropertyValue(O objectType, String propertyPathString, T propertyValue, boolean getAllConflicting) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { return getObjectsInConflictOnPropertyValue(objectType, propertyPathString, propertyValue, DefaultMatchingRule.NAME.getLocalPart(), getAllConflicting); } public <O extends ObjectType, T> List<O> getObjectsInConflictOnPropertyValue(O objectType, String propertyPathString, T propertyValue, String matchingRuleName, boolean getAllConflicting) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { Validate.notEmpty(propertyPathString, "Empty property path"); OperationResult result = getCurrentResult(MidpointFunctions.class.getName()+".getObjectsInConflictOnPropertyValue"); ItemPath propertyPath = new XPathHolder(propertyPathString).toItemPath(); QName matchingRuleQName = new QName(matchingRuleName); // no namespace for now return getObjectsInConflictOnPropertyValue(objectType, propertyPath, propertyValue, matchingRuleQName, getAllConflicting, getCurrentTask(), result); } private <O extends ObjectType, T> List<O> getObjectsInConflictOnPropertyValue(final O objectType, ItemPath propertyPath, T propertyValue, QName matchingRule, final boolean getAllConflicting, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { Validate.notNull(objectType, "Null object"); Validate.notNull(propertyPath, "Null property path"); Validate.notNull(propertyValue, "Null property value"); PrismPropertyDefinition<T> propertyDefinition = objectType.asPrismObject().getDefinition().findPropertyDefinition(propertyPath); if (matchingRule == null) { if (propertyDefinition != null && PolyStringType.COMPLEX_TYPE.equals(propertyDefinition.getTypeName())) { matchingRule = PolyStringOrigMatchingRule.NAME; } else { matchingRule = DefaultMatchingRule.NAME; } } ObjectQuery query = QueryBuilder.queryFor(objectType.getClass(), prismContext) .item(propertyPath, propertyDefinition).eq(propertyValue).matching(matchingRule) .build(); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Determining uniqueness of property {} using query:\n{}", propertyPath, query.debugDump()); } final List<O> conflictingObjects = new ArrayList<>(); ResultHandler<O> handler = new ResultHandler<O>() { @Override public boolean handle(PrismObject<O> object, OperationResult parentResult) { if (objectType.getOid() == null) { // We have found a conflicting object conflictingObjects.add(object.asObjectable()); return getAllConflicting; } else { if (objectType.getOid().equals(object.getOid())) { // We have found ourselves. No conflict (yet). Just go on. return true; } else { // We have found someone else. Conflict. conflictingObjects.add(object.asObjectable()); return getAllConflicting; } } } }; modelObjectResolver.searchIterative((Class) objectType.getClass(), query, null, handler, task, result); return conflictingObjects; } public <T> boolean isUniqueAccountValue(ResourceType resourceType, ShadowType shadowType, String attributeName, T attributeValue) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { Validate.notEmpty(attributeName,"Empty attribute name"); OperationResult result = getCurrentResult(MidpointFunctions.class.getName()+".isUniqueAccountValue"); QName attributeQName = new QName(ResourceTypeUtil.getResourceNamespace(resourceType), attributeName); return isUniqueAccountValue(resourceType, shadowType, attributeQName, attributeValue, getCurrentTask(), result); } private <T> boolean isUniqueAccountValue(ResourceType resourceType, final ShadowType shadowType, QName attributeName, T attributeValue, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { Validate.notNull(resourceType, "Null resource"); Validate.notNull(shadowType, "Null shadow"); Validate.notNull(attributeName, "Null attribute name"); Validate.notNull(attributeValue, "Null attribute value"); RefinedResourceSchema rSchema = RefinedResourceSchemaImpl.getRefinedSchema(resourceType); RefinedObjectClassDefinition rAccountDef = rSchema.getDefaultRefinedDefinition(ShadowKindType.ACCOUNT); RefinedAttributeDefinition attrDef = rAccountDef.findAttributeDefinition(attributeName); ObjectQuery query = QueryBuilder.queryFor(ShadowType.class, prismContext) .itemWithDef(attrDef, ShadowType.F_ATTRIBUTES, attrDef.getName()).eq(attributeValue) .and().item(ShadowType.F_OBJECT_CLASS).eq(rAccountDef.getObjectClassDefinition().getTypeName()) .and().item(ShadowType.F_RESOURCE_REF).ref(resourceType.getOid()) .build(); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Determining uniqueness of attribute {} using query:\n{}", attributeName, query.debugDump()); } final Holder<Boolean> isUniqueHolder = new Holder<Boolean>(true); ResultHandler<ShadowType> handler = new ResultHandler<ShadowType>() { @Override public boolean handle(PrismObject<ShadowType> object, OperationResult parentResult) { if (shadowType == null || shadowType.getOid() == null) { // We have found a conflicting object isUniqueHolder.setValue(false); return false; } else { if (shadowType.getOid().equals(object.getOid())) { // We have found ourselves. No conflict (yet). Just go on. return true; } else { // We have found someone else. Conflict. isUniqueHolder.setValue(false); return false; } } } }; modelObjectResolver.searchIterative(ShadowType.class, query, null, handler, task, result); return isUniqueHolder.getValue(); } private LensProjectionContext getProjectionContext() { return ModelExpressionThreadLocalHolder.getProjectionContext(); } @Override public Task getCurrentTask() { return ModelExpressionThreadLocalHolder.getCurrentTask(); } private OperationResult getCurrentResult() { return ModelExpressionThreadLocalHolder.getCurrentResult(); } private OperationResult getCurrentResult(String operationName) { OperationResult currentResult = ModelExpressionThreadLocalHolder.getCurrentResult(); if (currentResult == null) { return new OperationResult(operationName); } else { return currentResult; } } private OperationResult createSubresult(String operationName) { OperationResult currentResult = ModelExpressionThreadLocalHolder.getCurrentResult(); if (currentResult == null) { return new OperationResult(operationName); } else { return currentResult.createSubresult(operationName); } } private OperationResult createMinorSubresult(String operationName) { OperationResult currentResult = ModelExpressionThreadLocalHolder.getCurrentResult(); if (currentResult == null) { return new OperationResult(operationName); } else { return currentResult.createMinorSubresult(operationName); } } // functions working with ModelContext @Override public ModelContext unwrapModelContext(LensContextType lensContextType) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException { return LensContext.fromLensContextType(lensContextType, prismContext, provisioningService, getCurrentResult(MidpointFunctions.class.getName()+".getObject")); } public LensContextType wrapModelContext(LensContext<?> lensContext) throws SchemaException { return lensContext.toLensContextType(); } // Convenience functions @Override public <T extends ObjectType> T createEmptyObject(Class<T> type) throws SchemaException { PrismObjectDefinition<T> objectDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(type); PrismObject<T> object = objectDefinition.instantiate(); return object.asObjectable(); } @Override public <T extends ObjectType> T createEmptyObjectWithName(Class<T> type, String name) throws SchemaException { T objectType = createEmptyObject(type); objectType.setName(new PolyStringType(name)); return objectType; } @Override public <T extends ObjectType> T createEmptyObjectWithName(Class<T> type, PolyString name) throws SchemaException { T objectType = createEmptyObject(type); objectType.setName(new PolyStringType(name)); return objectType; } @Override public <T extends ObjectType> T createEmptyObjectWithName(Class<T> type, PolyStringType name) throws SchemaException { T objectType = createEmptyObject(type); objectType.setName(name); return objectType; } // Functions accessing modelService @Override public <T extends ObjectType> T resolveReference(ObjectReferenceType reference) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { if (reference == null) { return null; } QName type = reference.getType(); // TODO what about implicitly specified types, like in resourceRef? PrismObjectDefinition<T> objectDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByType(reference.getType()); if (objectDefinition == null) { throw new SchemaException("No definition for type " + type); } return modelService.getObject( objectDefinition.getCompileTimeClass(), reference.getOid(), null, getCurrentTask(), getCurrentResult()).asObjectable(); } @Override public <T extends ObjectType> T resolveReferenceIfExists(ObjectReferenceType reference) throws SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { try { return resolveReference(reference); } catch (ObjectNotFoundException e) { return null; } } @Override public <T extends ObjectType> T getObject(Class<T> type, String oid, Collection<SelectorOptions<GetOperationOptions>> options) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { return modelService.getObject(type, oid, options, getCurrentTask(), getCurrentResult()).asObjectable(); } @Override public <T extends ObjectType> T getObject(Class<T> type, String oid) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { PrismObject<T> prismObject = modelService.getObject(type, oid, null, getCurrentTask(), getCurrentResult()); return prismObject.asObjectable(); } @Override public void executeChanges( Collection<ObjectDelta<? extends ObjectType>> deltas, ModelExecuteOptions options) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { modelService.executeChanges(deltas, options, getCurrentTask(), getCurrentResult()); } @Override public void executeChanges( Collection<ObjectDelta<? extends ObjectType>> deltas) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { modelService.executeChanges(deltas, null, getCurrentTask(), getCurrentResult()); } @Override public void executeChanges(ObjectDelta<? extends ObjectType>... deltas) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { Collection<ObjectDelta<? extends ObjectType>> deltaCollection = MiscSchemaUtil.createCollection(deltas); modelService.executeChanges(deltaCollection, null, getCurrentTask(), getCurrentResult()); } @Override public <T extends ObjectType> String addObject(PrismObject<T> newObject, ModelExecuteOptions options) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { ObjectDelta<T> delta = ObjectDelta.createAddDelta(newObject); Collection<ObjectDelta<? extends ObjectType>> deltaCollection = MiscSchemaUtil.createCollection(delta); modelService.executeChanges(deltaCollection, options, getCurrentTask(), getCurrentResult()); return delta.getOid(); } @Override public <T extends ObjectType> String addObject(PrismObject<T> newObject) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { return addObject(newObject, null); } @Override public <T extends ObjectType> String addObject(T newObject, ModelExecuteOptions options) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { return addObject(newObject.asPrismObject(), options); } @Override public <T extends ObjectType> String addObject(T newObject) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { return addObject(newObject.asPrismObject(), null); } @Override public <T extends ObjectType> void modifyObject(ObjectDelta<T> modifyDelta, ModelExecuteOptions options) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { Collection<ObjectDelta<? extends ObjectType>> deltaCollection = MiscSchemaUtil.createCollection(modifyDelta); modelService.executeChanges(deltaCollection, options, getCurrentTask(), getCurrentResult()); } @Override public <T extends ObjectType> void modifyObject(ObjectDelta<T> modifyDelta) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { Collection<ObjectDelta<? extends ObjectType>> deltaCollection = MiscSchemaUtil.createCollection(modifyDelta); modelService.executeChanges(deltaCollection, null, getCurrentTask(), getCurrentResult()); } @Override public <T extends ObjectType> void deleteObject(Class<T> type, String oid, ModelExecuteOptions options) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { ObjectDelta<T> deleteDelta = ObjectDelta.createDeleteDelta(type, oid, prismContext); Collection<ObjectDelta<? extends ObjectType>> deltaCollection = MiscSchemaUtil.createCollection(deleteDelta); modelService.executeChanges(deltaCollection, options, getCurrentTask(), getCurrentResult()); } @Override public <T extends ObjectType> void deleteObject(Class<T> type, String oid) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { ObjectDelta<T> deleteDelta = ObjectDelta.createDeleteDelta(type, oid, prismContext); Collection<ObjectDelta<? extends ObjectType>> deltaCollection = MiscSchemaUtil.createCollection(deleteDelta); modelService.executeChanges(deltaCollection, null, getCurrentTask(), getCurrentResult()); } @Override public <F extends FocusType> void recompute(Class<F> type, String oid) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { modelService.recompute(type, oid, null, getCurrentTask(), getCurrentResult()); } @Override public PrismObject<UserType> findShadowOwner(String accountOid) throws ObjectNotFoundException, SecurityViolationException, SchemaException, ConfigurationException { return modelService.findShadowOwner(accountOid, getCurrentTask(), getCurrentResult()); } @Override public <T extends ObjectType> List<T> searchObjects( Class<T> type, ObjectQuery query, Collection<SelectorOptions<GetOperationOptions>> options) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException { return MiscSchemaUtil.toObjectableList( modelService.searchObjects(type, query, options, getCurrentTask(), getCurrentResult())); } @Override public <T extends ObjectType> List<T> searchObjects( Class<T> type, ObjectQuery query) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException { return MiscSchemaUtil.toObjectableList( modelService.searchObjects(type, query, null, getCurrentTask(), getCurrentResult())); } @Override public <T extends ObjectType> void searchObjectsIterative(Class<T> type, ObjectQuery query, ResultHandler<T> handler, Collection<SelectorOptions<GetOperationOptions>> options) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { modelService.searchObjectsIterative(type, query, handler, options, getCurrentTask(), getCurrentResult()); } @Override public <T extends ObjectType> void searchObjectsIterative(Class<T> type, ObjectQuery query, ResultHandler<T> handler) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { modelService.searchObjectsIterative(type, query, handler, null, getCurrentTask(), getCurrentResult()); } @Override public <T extends ObjectType> T searchObjectByName(Class<T> type, String name) throws SecurityViolationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SchemaException { ObjectQuery nameQuery = ObjectQueryUtil.createNameQuery(name, prismContext); List<PrismObject<T>> foundObjects = modelService.searchObjects(type, nameQuery, null, getCurrentTask(), getCurrentResult()); if (foundObjects.isEmpty()) { return null; } if (foundObjects.size() > 1) { throw new IllegalStateException("More than one object found for type "+type+" and name '"+name+"'"); } return foundObjects.iterator().next().asObjectable(); } @Override public <T extends ObjectType> T searchObjectByName(Class<T> type, PolyString name) throws SecurityViolationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SchemaException { ObjectQuery nameQuery = ObjectQueryUtil.createNameQuery(name, prismContext); List<PrismObject<T>> foundObjects = modelService.searchObjects(type, nameQuery, null, getCurrentTask(), getCurrentResult()); if (foundObjects.isEmpty()) { return null; } if (foundObjects.size() > 1) { throw new IllegalStateException("More than one object found for type "+type+" and name '"+name+"'"); } return foundObjects.iterator().next().asObjectable(); } @Override public <T extends ObjectType> T searchObjectByName(Class<T> type, PolyStringType name) throws SecurityViolationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SchemaException { ObjectQuery nameQuery = ObjectQueryUtil.createNameQuery(name, prismContext); List<PrismObject<T>> foundObjects = modelService.searchObjects(type, nameQuery, null, getCurrentTask(), getCurrentResult()); if (foundObjects.isEmpty()) { return null; } if (foundObjects.size() > 1) { throw new IllegalStateException("More than one object found for type "+type+" and name '"+name+"'"); } return foundObjects.iterator().next().asObjectable(); } @Override public <T extends ObjectType> int countObjects(Class<T> type, ObjectQuery query, Collection<SelectorOptions<GetOperationOptions>> options) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ConfigurationException, CommunicationException { return modelService.countObjects(type, query, options, getCurrentTask(), getCurrentResult()); } @Override public <T extends ObjectType> int countObjects(Class<T> type, ObjectQuery query) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ConfigurationException, CommunicationException { return modelService.countObjects(type, query, null, getCurrentTask(), getCurrentResult()); } @Override public OperationResult testResource(String resourceOid) throws ObjectNotFoundException { return modelService.testResource(resourceOid, getCurrentTask()); } @Override public ObjectDeltaType getResourceDelta(ModelContext context, String resourceOid) throws SchemaException { List<ObjectDelta<ShadowType>> deltas = new ArrayList<>(); for (Object modelProjectionContextObject : context.getProjectionContexts()) { LensProjectionContext lensProjectionContext = (LensProjectionContext) modelProjectionContextObject; if (lensProjectionContext.getResourceShadowDiscriminator() != null && resourceOid.equals(lensProjectionContext.getResourceShadowDiscriminator().getResourceOid())) { deltas.add(lensProjectionContext.getDelta()); // union of primary and secondary deltas } } ObjectDelta<ShadowType> sum = ObjectDelta.summarize(deltas); return DeltaConvertor.toObjectDeltaType(sum); } public long getSequenceCounter(String sequenceOid) throws ObjectNotFoundException, SchemaException { return SequentialValueExpressionEvaluator.getSequenceCounter(sequenceOid, repositoryService, getCurrentResult()); } // orgstruct related methods @Override public Collection<String> getManagersOids(UserType user) throws SchemaException, ObjectNotFoundException, SecurityViolationException { return orgStructFunctions.getManagersOids(user, false); } @Override public Collection<String> getOrgUnits(UserType user, QName relation) { return orgStructFunctions.getOrgUnits(user, relation, false); } @Override public OrgType getParentOrgByOrgType(ObjectType object, String orgType) throws SchemaException, SecurityViolationException { return orgStructFunctions.getParentOrgByOrgType(object, orgType, false); } @Override public OrgType getOrgByOid(String oid) throws SchemaException { return orgStructFunctions.getOrgByOid(oid, false); } @Override public Collection<OrgType> getParentOrgs(ObjectType object) throws SchemaException, SecurityViolationException { return orgStructFunctions.getParentOrgs(object, false); } @Override public Collection<String> getOrgUnits(UserType user) { return orgStructFunctions.getOrgUnits(user, false); } @Override public Collection<UserType> getManagersOfOrg(String orgOid) throws SchemaException, SecurityViolationException { return orgStructFunctions.getManagersOfOrg(orgOid, false); } @Override public boolean isManagerOfOrgType(UserType user, String orgType) throws SchemaException { return orgStructFunctions.isManagerOfOrgType(user, orgType, false); } @Override public Collection<UserType> getManagers(UserType user) throws SchemaException, ObjectNotFoundException, SecurityViolationException { return orgStructFunctions.getManagers(user, false); } @Override public Collection<UserType> getManagersByOrgType(UserType user, String orgType) throws SchemaException, ObjectNotFoundException, SecurityViolationException { return orgStructFunctions.getManagersByOrgType(user, orgType, false); } @Override public boolean isManagerOf(UserType user, String orgOid) { return orgStructFunctions.isManagerOf(user, orgOid, false); } @Override public Collection<OrgType> getParentOrgsByRelation(ObjectType object, String relation) throws SchemaException, SecurityViolationException { return orgStructFunctions.getParentOrgsByRelation(object, relation, false); } @Override public Collection<UserType> getManagers(UserType user, String orgType, boolean allowSelf) throws SchemaException, ObjectNotFoundException, SecurityViolationException { return orgStructFunctions.getManagers(user, orgType, allowSelf, false); } @Override public Collection<OrgType> getParentOrgs(ObjectType object, String relation, String orgType) throws SchemaException, SecurityViolationException { return orgStructFunctions.getParentOrgs(object, relation, orgType, false); } @Override public Collection<String> getManagersOidsExceptUser(UserType user) throws SchemaException, ObjectNotFoundException, SecurityViolationException { return orgStructFunctions.getManagersOidsExceptUser(user, false); } @Override public Collection<String> getManagersOidsExceptUser(@NotNull Collection<ObjectReferenceType> userRefList) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException { return orgStructFunctions.getManagersOidsExceptUser(userRefList, false); } @Override public OrgType getOrgByName(String name) throws SchemaException, SecurityViolationException { return orgStructFunctions.getOrgByName(name, false); } @Override public Collection<OrgType> getParentOrgsByRelation(ObjectType object, QName relation) throws SchemaException, SecurityViolationException { return orgStructFunctions.getParentOrgsByRelation(object, relation, false); } @Override public Collection<OrgType> getParentOrgs(ObjectType object, QName relation, String orgType) throws SchemaException, SecurityViolationException { return orgStructFunctions.getParentOrgs(object, relation, orgType, false); } @Override public boolean isManager(UserType user) { return orgStructFunctions.isManager(user); } @Override public Protector getProtector() { return protector; } @Override public String getPlaintext(ProtectedStringType protectedStringType) throws EncryptionException { if (protectedStringType != null) { return protector.decryptString(protectedStringType); } else { return null; } } @Override public Map<String, String> parseXmlToMap(String xml) { Map<String, String> resultingMap = new HashMap<String, String>(); if(xml!=null&&!xml.isEmpty()){ XMLInputFactory factory = XMLInputFactory.newInstance(); String value = ""; String startName = ""; InputStream stream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); boolean isRootElement = true; try { XMLEventReader eventReader = factory.createXMLEventReader(stream); while (eventReader.hasNext()) { XMLEvent event = eventReader.nextEvent(); Integer code = event.getEventType(); if (code == XMLStreamConstants.START_ELEMENT) { StartElement startElement = event.asStartElement(); startName = startElement.getName().getLocalPart(); if (!isRootElement) { resultingMap.put(startName, null); } else { isRootElement = false; } } else if (code == XMLStreamConstants.CHARACTERS) { Characters characters = event.asCharacters(); if (!characters.isWhiteSpace()) { StringBuilder valueBuilder; if (value != null) { valueBuilder = new StringBuilder(value).append(" ").append(characters.getData().toString()); } else { valueBuilder = new StringBuilder(characters.getData().toString()); } value = valueBuilder.toString(); } } else if (code == XMLStreamConstants.END_ELEMENT) { EndElement endElement = event.asEndElement(); String endName = endElement.getName().getLocalPart(); if (endName.equals(startName)) { if (value != null) { resultingMap.put(endName, value); value = null; } } else { LOGGER.trace("No value between xml tags, tag name : {0}", endName); } } else if (code == XMLStreamConstants.END_DOCUMENT) { isRootElement = true; } } } catch (XMLStreamException e) { StringBuilder error = new StringBuilder("Xml stream exception wile parsing xml string") .append(e.getLocalizedMessage()); throw new SystemException(error.toString()); } }else { LOGGER.trace("Input xml string null or empty."); } return resultingMap; } @Override public List<ObjectReferenceType> getMembersAsReferences(String orgOid) throws SchemaException, SecurityViolationException, CommunicationException, ConfigurationException, ObjectNotFoundException { return getMembers(orgOid).stream() .map(obj -> ObjectTypeUtil.createObjectRef(obj)) .collect(Collectors.toList()); } @Override public List<UserType> getMembers(String orgOid) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException { ObjectQuery query = QueryBuilder.queryFor(UserType.class, prismContext) .isDirectChildOf(orgOid) .build(); return searchObjects(UserType.class, query, null); } @Override public <F extends FocusType> String computeProjectionLifecycle(F focus, ShadowType shadow, ResourceType resource) { if (focus == null || shadow == null) { return null; } if (!(focus instanceof UserType)) { return null; } if (shadow.getKind() != null && shadow.getKind() != ShadowKindType.ACCOUNT) { return null; } ProtectedStringType passwordPs = FocusTypeUtil.getPasswordValue((UserType)focus); if (passwordPs != null && passwordPs.canGetCleartext()) { return null; } CredentialsCapabilityType credentialsCapabilityType = ResourceTypeUtil.getEffectiveCapability(resource, CredentialsCapabilityType.class); if (credentialsCapabilityType == null) { return null; } PasswordCapabilityType passwordCapabilityType = credentialsCapabilityType.getPassword(); if (passwordCapabilityType == null) { return null; } if (passwordCapabilityType.isEnabled() == Boolean.FALSE) { return null; } return SchemaConstants.LIFECYCLE_PROPOSED; } public MidPointPrincipal getPrincipal() throws SecurityViolationException { return securityEnforcer.getPrincipal(); } @Override public String getChannel() { Task task = getCurrentTask(); return task != null ? task.getChannel() : null; } @Override public WorkflowService getWorkflowService() { return workflowService; } @Override public List<ShadowType> getShadowsToActivate(Collection<ModelElementContext> projectionContexts) { List<ShadowType> shadows = new ArrayList<>(); for (ModelElementContext<ShadowType> projectionCtx : projectionContexts) { List<? extends ObjectDeltaOperation> executedShadowDelas = projectionCtx.getExecutedDeltas(); for (ObjectDeltaOperation<ShadowType> shadowDelta : executedShadowDelas) { if (shadowDelta.getExecutionResult().getStatus() == OperationResultStatus.SUCCESS && shadowDelta.getObjectDelta().getChangeType() == ChangeType.ADD) { PrismObject<ShadowType> shadow = shadowDelta.getObjectDelta().getObjectToAdd(); PrismProperty<String> pLifecycleState = shadow.findProperty(ShadowType.F_LIFECYCLE_STATE); if (pLifecycleState != null && !pLifecycleState.isEmpty() && SchemaConstants.LIFECYCLE_PROPOSED.equals(pLifecycleState.getRealValue())) { shadows.add(shadow.asObjectable()); } } } } return shadows; } @Override public String createRegistrationConfirmationLink(UserType userType) { return createTokenConfirmationLink(SchemaConstants.REGISTRATION_CONFIRAMTION_PREFIX, userType); } @Override public String createPasswordResetLink(UserType userType) { return createTokenConfirmationLink(SchemaConstants.PASSWORD_RESET_CONFIRMATION_PREFIX, userType); } @Override public String createAccountActivationLink(UserType userType) { return createBaseConfirmationLink(SchemaConstants.ACCOUNT_ACTIVATION_PREFIX, userType.getOid()); } private String createBaseConfirmationLink(String prefix, UserType userType) { return prefix + "?" + SchemaConstants.USER_ID + "=" + userType.getName().getOrig(); } private String createBaseConfirmationLink(String prefix, String oid) { return prefix + "?" + SchemaConstants.USER_ID + "=" + oid; } private String createTokenConfirmationLink(String prefix, UserType userType) { return createBaseConfirmationLink(prefix, userType) + "&" + SchemaConstants.TOKEN + "=" + getNonce(userType); } private String getNonce(UserType user) { if (user.getCredentials() == null) { return null; } if (user.getCredentials().getNonce() == null) { return null; } if (user.getCredentials().getNonce().getValue() == null) { return null; } try { return getPlaintext(user.getCredentials().getNonce().getValue()); } catch (EncryptionException e) { return null; } } }