diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainerValue.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainerValue.java index b84bc445a92..fed6596f738 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainerValue.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainerValue.java @@ -1582,4 +1582,17 @@ public static List> toPcvList(L } return rv; } + + public static List fromPcvList(List> values) { + if (values == null) { + return null; + } + List realValues = new ArrayList<>(values.size()); + for (PrismContainerValue value : values) { + realValues.add(value.asContainerable()); + } + + return realValues; + + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/CredentialsProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/CredentialsProcessor.java index a94567313fe..7eaa55324a3 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/CredentialsProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/CredentialsProcessor.java @@ -15,12 +15,17 @@ */ package com.evolveum.midpoint.model.impl.lens.projector; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; - +import java.util.Comparator; +import java.util.List; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.model.api.PolicyViolationException; import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision; @@ -33,11 +38,12 @@ import com.evolveum.midpoint.model.impl.lens.LensFocusContext; import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; import com.evolveum.midpoint.model.impl.lens.LensUtil; -import com.evolveum.midpoint.prism.Containerable; +import com.evolveum.midpoint.prism.ComplexTypeDefinition; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.OriginType; import com.evolveum.midpoint.prism.PrismContainer; +import com.evolveum.midpoint.prism.PrismContainerDefinition; import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; @@ -53,13 +59,9 @@ import com.evolveum.midpoint.prism.delta.PartiallyResolvedDelta; import com.evolveum.midpoint.prism.delta.PropertyDelta; import com.evolveum.midpoint.prism.path.ItemPath; -import com.evolveum.midpoint.prism.path.ItemPathSegment; -import com.evolveum.midpoint.prism.schema.PrismSchema; -import com.evolveum.midpoint.prism.schema.SchemaRegistry; import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; import com.evolveum.midpoint.schema.constants.ExpressionConstants; import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.processor.*; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; @@ -67,154 +69,184 @@ import com.evolveum.midpoint.util.exception.SchemaException; 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.common.common_3.AbstractCredentialType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingStrengthType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordHistoryEntryType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.StringPolicyType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - /** * Processor that takes password from user and synchronizes it to accounts. *

- * The implementation is very simple now. It only cares about password value, not - * expiration or other password facets. It completely ignores other credential types. + * The implementation is very simple now. It only cares about password value, + * not expiration or other password facets. It completely ignores other + * credential types. * * @author Radovan Semancik */ @Component public class CredentialsProcessor { - private static final Trace LOGGER = TraceManager.getTrace(CredentialsProcessor.class); - - @Autowired(required = true) - private PrismContext prismContext; - - @Autowired(required = true) - private MappingFactory mappingFactory; - - @Autowired(required = true) - private MappingEvaluator mappingEvaluator; - - @Autowired(required = true) - private PasswordPolicyProcessor passwordPolicyProcessor; - - public void processFocusCredentials(LensContext context, - XMLGregorianCalendar now, Task task, OperationResult result) - throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException { - LensFocusContext focusContext = context.getFocusContext(); - if (focusContext != null && FocusType.class.isAssignableFrom(focusContext.getObjectTypeClass())) { - processFocusPassword((LensContext)context, now, task, result); - } - } - - private void processFocusPassword(LensContext context, - XMLGregorianCalendar now, Task task, OperationResult result) - throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException { - LensFocusContext focusContext = context.getFocusContext(); - - processFocusCredentialsCommon(context, new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_PASSWORD), now, task, result); - - passwordPolicyProcessor.processPasswordPolicy(focusContext, context, task, result); - } - - public void processProjectionCredentials(LensContext context, LensProjectionContext projectionContext, - XMLGregorianCalendar now, Task task, OperationResult result) - throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException { - LensFocusContext focusContext = context.getFocusContext(); - if (focusContext != null && FocusType.class.isAssignableFrom(focusContext.getObjectTypeClass())) { - processProjectionPassword((LensContext)context, projectionContext, now, task, result); - } - - passwordPolicyProcessor.processPasswordPolicy(projectionContext, context, task, result); - } - - private void processProjectionPassword(LensContext context, - final LensProjectionContext accCtx, XMLGregorianCalendar now, Task task, OperationResult result) - throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { - LensFocusContext focusContext = context.getFocusContext(); - ObjectDelta focusDelta = focusContext.getDelta(); - - PropertyDelta userPasswordValueDelta = null; - if (focusDelta != null) { - userPasswordValueDelta = focusDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); - } - - PrismObject 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 accountDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class); - PrismPropertyDefinition accountPasswordPropertyDefinition = accountDefinition.findPropertyDefinition(SchemaConstants.PATH_PASSWORD_VALUE); - - ResourceShadowDiscriminator rat = accCtx.getResourceShadowDiscriminator(); - - ObjectDelta accountDelta = accCtx.getDelta(); - PropertyDelta accountPasswordValueDelta = null; - if (accountDelta != null) { - accountPasswordValueDelta = accountDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); - } - if (accountDelta != null && accountDelta.getChangeType() == ChangeType.MODIFY) { - if (accountPasswordValueDelta != null && (accountPasswordValueDelta.isAdd() || accountDelta.isDelete())) { - throw new SchemaException("Password for account "+rat+" cannot be added or deleted, it can only be replaced"); - } - } - if (accountDelta != null && (accountDelta.getChangeType() == ChangeType.ADD || accCtx.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD)) { - // adding new account, synchronize password regardless whether the password was changed or not. - } else if (userPasswordValueDelta != null) { - // user password was changed. synchronize it regardless of the account change. - } else { - LOGGER.trace("No change in password and the account is not added, skipping credentials processing for account " + rat); - return; - } - - RefinedObjectClassDefinition refinedAccountDef = accCtx.getStructuralObjectClassDefinition(); - if (refinedAccountDef == null){ - LOGGER.trace("No RefinedAccountDefinition, therefore also no password outbound definition, skipping credentials processing for account " + rat); - return; - } - - MappingType outboundMappingType = refinedAccountDef.getPasswordOutbound(); - - if (outboundMappingType == null) { - LOGGER.trace("No outbound definition in password definition in credentials in account type {}, skipping credentials processing", rat); - return; - } - - Mapping,PrismPropertyDefinition> passwordMapping = mappingFactory.createMapping(outboundMappingType, - "outbound password mapping in account type " + rat); - if (!passwordMapping.isApplicableToChannel(context.getChannel())) { - return; - } - - passwordMapping.setDefaultTargetDefinition(accountPasswordPropertyDefinition); - ItemDeltaItem,PrismPropertyDefinition> userPasswordIdi = focusContext.getObjectDeltaObject().findIdi(SchemaConstants.PATH_PASSWORD_VALUE); - Source,PrismPropertyDefinition> source = new Source<>(userPasswordIdi, ExpressionConstants.VAR_INPUT); + private static final Trace LOGGER = TraceManager.getTrace(CredentialsProcessor.class); + + @Autowired(required = true) + private PrismContext prismContext; + + @Autowired(required = true) + private MappingFactory mappingFactory; + + @Autowired(required = true) + private MappingEvaluator mappingEvaluator; + + @Autowired(required = true) + private PasswordPolicyProcessor passwordPolicyProcessor; + + public void processFocusCredentials(LensContext context, + XMLGregorianCalendar now, Task task, OperationResult result) throws ExpressionEvaluationException, + ObjectNotFoundException, SchemaException, PolicyViolationException { + LensFocusContext focusContext = context.getFocusContext(); + if (focusContext != null && FocusType.class.isAssignableFrom(focusContext.getObjectTypeClass())) { + processFocusPassword((LensContext) context, now, task, result); + } + } + + private void processFocusPassword(LensContext context, XMLGregorianCalendar now, + Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, + SchemaException, PolicyViolationException { + LensFocusContext focusContext = context.getFocusContext(); + + processFocusCredentialsCommon(context, + new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_PASSWORD), now, task, result); + + passwordPolicyProcessor.processPasswordPolicy(focusContext, context, task, result); + } + + public void processProjectionCredentials(LensContext context, + LensProjectionContext projectionContext, XMLGregorianCalendar now, Task task, + OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, + SchemaException, PolicyViolationException { + LensFocusContext focusContext = context.getFocusContext(); + if (focusContext != null && FocusType.class.isAssignableFrom(focusContext.getObjectTypeClass())) { + processProjectionPassword((LensContext) context, projectionContext, now, + task, result); + } + + passwordPolicyProcessor.processPasswordPolicy(projectionContext, context, task, result); + } + + private void processProjectionPassword(LensContext context, + final LensProjectionContext accCtx, XMLGregorianCalendar now, Task task, OperationResult result) + throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { + LensFocusContext focusContext = context.getFocusContext(); + ObjectDelta focusDelta = focusContext.getDelta(); + + PropertyDelta userPasswordValueDelta = null; + if (focusDelta != null) { + userPasswordValueDelta = focusDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); + } + + PrismObject 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 accountDefinition = prismContext.getSchemaRegistry() + .findObjectDefinitionByCompileTimeClass(ShadowType.class); + PrismPropertyDefinition accountPasswordPropertyDefinition = accountDefinition + .findPropertyDefinition(SchemaConstants.PATH_PASSWORD_VALUE); + + ResourceShadowDiscriminator rat = accCtx.getResourceShadowDiscriminator(); + + ObjectDelta accountDelta = accCtx.getDelta(); + PropertyDelta accountPasswordValueDelta = null; + if (accountDelta != null) { + accountPasswordValueDelta = accountDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); + } + if (accountDelta != null && accountDelta.getChangeType() == ChangeType.MODIFY) { + if (accountPasswordValueDelta != null + && (accountPasswordValueDelta.isAdd() || accountDelta.isDelete())) { + throw new SchemaException("Password for account " + rat + + " cannot be added or deleted, it can only be replaced"); + } + } + if (accountDelta != null && (accountDelta.getChangeType() == ChangeType.ADD + || accCtx.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD)) { + // adding new account, synchronize password regardless whether the + // password was changed or not. + } else if (userPasswordValueDelta != null) { + // user password was changed. synchronize it regardless of the + // account change. + } else { + LOGGER.trace( + "No change in password and the account is not added, skipping credentials processing for account " + + rat); + return; + } + + RefinedObjectClassDefinition refinedAccountDef = accCtx.getStructuralObjectClassDefinition(); + if (refinedAccountDef == null) { + LOGGER.trace( + "No RefinedAccountDefinition, therefore also no password outbound definition, skipping credentials processing for account " + + rat); + return; + } + + MappingType outboundMappingType = refinedAccountDef.getPasswordOutbound(); + + if (outboundMappingType == null) { + LOGGER.trace( + "No outbound definition in password definition in credentials in account type {}, skipping credentials processing", + rat); + return; + } + + Mapping, PrismPropertyDefinition> passwordMapping = mappingFactory + .createMapping(outboundMappingType, "outbound password mapping in account type " + rat); + if (!passwordMapping.isApplicableToChannel(context.getChannel())) { + return; + } + + passwordMapping.setDefaultTargetDefinition(accountPasswordPropertyDefinition); + ItemDeltaItem, PrismPropertyDefinition> userPasswordIdi = focusContext + .getObjectDeltaObject().findIdi(SchemaConstants.PATH_PASSWORD_VALUE); + Source, PrismPropertyDefinition> source = new Source<>( + userPasswordIdi, ExpressionConstants.VAR_INPUT); passwordMapping.setDefaultSource(source); passwordMapping.setOriginType(OriginType.OUTBOUND); passwordMapping.setOriginObject(accCtx.getResource()); - + if (passwordMapping.getStrength() != MappingStrengthType.STRONG) { - if (accountPasswordValueDelta != null && !accountPasswordValueDelta.isEmpty()) { - return; - } - } - + if (accountPasswordValueDelta != null && !accountPasswordValueDelta.isEmpty()) { + return; + } + } + StringPolicyResolver stringPolicyResolver = new StringPolicyResolver() { private ItemPath outputPath; private ItemDefinition outputDefinition; + @Override public void setOutputPath(ItemPath outputPath) { this.outputPath = outputPath; } - + @Override public void setOutputDefinition(ItemDefinition outputDefinition) { this.outputDefinition = outputDefinition; } - + @Override public StringPolicyType resolve() { ValuePolicyType passwordPolicy = accCtx.getEffectivePasswordPolicy(); @@ -225,7 +257,7 @@ public StringPolicyType resolve() { } }; passwordMapping.setStringPolicyResolver(stringPolicyResolver); - + mappingEvaluator.evaluateMapping(passwordMapping, context, task, result); // TODO review all this code !! MID-3156 @@ -234,68 +266,116 @@ public StringPolicyType resolve() { PrismProperty accountPasswordNew = (PrismProperty) passwordMapping.getOutput(); if (accountPasswordNew == null || accountPasswordNew.isEmpty()) { if (passwordMapping.getOutputTriple() == null) { - LOGGER.trace("Credentials 'password' expression resulted in null output triple, skipping credentials processing for {}", rat); + LOGGER.trace( + "Credentials 'password' expression resulted in null output triple, skipping credentials processing for {}", + rat); return; } if (passwordMapping.getStrength() != MappingStrengthType.STRONG) { - LOGGER.trace("Credentials 'password' expression resulted in 'no value' via non-strong mapping, skipping credentials processing for {}", rat); + LOGGER.trace( + "Credentials 'password' expression resulted in 'no value' via non-strong mapping, skipping credentials processing for {}", + rat); return; } } - PropertyDelta accountPasswordDeltaNew = new PropertyDelta<>(SchemaConstants.PATH_PASSWORD_VALUE, accountPasswordPropertyDefinition, prismContext); + PropertyDelta accountPasswordDeltaNew = new PropertyDelta<>( + SchemaConstants.PATH_PASSWORD_VALUE, accountPasswordPropertyDefinition, prismContext); if (accountPasswordNew != null) { accountPasswordDeltaNew.setValuesToReplace(accountPasswordNew.getClonedValues()); } else { - accountPasswordDeltaNew.setValuesToReplace(Collections.>emptyList()); + accountPasswordDeltaNew + .setValuesToReplace(Collections.> emptyList()); + } + LOGGER.trace("Adding new password delta for account {}", rat); + accCtx.swallowToSecondaryDelta(accountPasswordDeltaNew); + + } + + private void processFocusCredentialsCommon(LensContext context, + ItemPath credentialsPath, XMLGregorianCalendar now, Task task, OperationResult result) + throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { + + LensFocusContext focusContext = context.getFocusContext(); + + if (focusContext.isAdd()) { + PrismObject focus = focusContext.getObjectNew(); + PrismContainer credentialsContainer = focus + .findContainer(credentialsPath); + if (credentialsContainer != null) { + for (PrismContainerValue cVal : credentialsContainer.getValues()) { + processCredentialsCommonAdd(focus, context, credentialsPath, cVal, now, task, result); + } + } + } else if (focusContext.isModify()) { + ObjectDelta focusDelta = focusContext.getDelta(); + PrismObject focus = focusContext.getObjectOld(); + if (focus == null) { + focus = focusContext.getObjectCurrent(); + } + if (focus == null) { + focus = focusContext.getObjectNew(); + } + ContainerDelta containerDelta = focusDelta + .findContainerDelta(credentialsPath); + if (containerDelta != null) { + if (containerDelta.isAdd()) { + for (PrismContainerValue cVal : containerDelta.getValuesToAdd()) { + processCredentialsCommonAdd(focus, context, credentialsPath, cVal, now, task, result); + } + } + if (containerDelta.isReplace()) { + for (PrismContainerValue cVal : containerDelta + .getValuesToReplace()) { + processCredentialsCommonAdd(focus, context, credentialsPath, cVal, now, task, result); + } + } + } else { + if (hasValueDelta(focusDelta, credentialsPath)) { + Collection> metaDeltas = LensUtil.createModifyMetadataDeltas( + context, credentialsPath.subPath(AbstractCredentialType.F_METADATA), + focusContext.getObjectDefinition(), now, task); + for (ItemDelta metaDelta : metaDeltas) { + context.getFocusContext().swallowToSecondaryDelta(metaDelta); + } + + processPasswordHistoryDeltas(focus, context, now, task, result); + } + } + } + } + + private int getMaxPasswordsToSave(LensFocusContext focusContext, + LensContext context, Task task, OperationResult result) throws SchemaException { + ValuePolicyType passwordPolicy; + if (focusContext.getOrgPasswordPolicy() == null) { + passwordPolicy = passwordPolicyProcessor.determineValuePolicy(focusContext.getDelta(), + focusContext.getObjectAny(), context, task, result); + focusContext.setOrgPasswordPolicy(passwordPolicy); + } else { + passwordPolicy = focusContext.getOrgPasswordPolicy(); + } + + if (passwordPolicy == null) { + return 0; + } + + if (passwordPolicy.getLifetime() == null) { + return 0; } - LOGGER.trace("Adding new password delta for account {}", rat); - accCtx.swallowToSecondaryDelta(accountPasswordDeltaNew); - - } - - private void processFocusCredentialsCommon(LensContext context, - ItemPath credentialsPath, XMLGregorianCalendar now, Task task, OperationResult result) - throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { - LensFocusContext focusContext = context.getFocusContext(); - if (focusContext.isAdd()) { - PrismObject focus = focusContext.getObjectNew(); - PrismContainer credentialsContainer = focus.findContainer(credentialsPath); - if (credentialsContainer != null) { - for (PrismContainerValue cVal: credentialsContainer.getValues()) { - processCredentialsCommonAdd(context, credentialsPath, cVal, now, task, result); - } - } - } else if (focusContext.isModify()) { - ObjectDelta focusDelta = focusContext.getDelta(); - ContainerDelta containerDelta = focusDelta.findContainerDelta(credentialsPath); - if (containerDelta != null) { - if (containerDelta.isAdd()) { - for (PrismContainerValue cVal: containerDelta.getValuesToAdd()) { - processCredentialsCommonAdd(context, credentialsPath, cVal, now, task, result); - } - } - if (containerDelta.isReplace()) { - for (PrismContainerValue cVal: containerDelta.getValuesToReplace()) { - processCredentialsCommonAdd(context, credentialsPath, cVal, now, task, result); - } - } - } else { - if (hasValueDelta(focusDelta, credentialsPath)) { - Collection> metaDeltas = LensUtil.createModifyMetadataDeltas(context, credentialsPath.subPath(AbstractCredentialType.F_METADATA), - focusContext.getObjectDefinition(), now, task); - for (ItemDelta metaDelta: metaDeltas) { - context.getFocusContext().swallowToSecondaryDelta(metaDelta); - } - } - } - } - } - - private boolean hasValueDelta(ObjectDelta focusDelta, ItemPath credentialsPath) { - if (focusDelta == null) { - return false; - } - for (PartiallyResolvedDelta partialDelta: focusDelta.findPartial(credentialsPath)) { + + if (passwordPolicy.getLifetime().getPasswordHistoryLength() == null) { + return 0; + } + + return passwordPolicy.getLifetime().getPasswordHistoryLength().intValue(); + } + + private boolean hasValueDelta(ObjectDelta focusDelta, ItemPath credentialsPath) { + if (focusDelta == null) { + return false; + } + for (PartiallyResolvedDelta partialDelta : focusDelta + .findPartial(credentialsPath)) { LOGGER.trace("Residual delta:\n{}", partialDelta.debugDump()); ItemPath residualPath = partialDelta.getResidualPath(); if (residualPath == null || residualPath.isEmpty()) { @@ -311,42 +391,130 @@ private boolean hasValueDelta(ObjectDelta focusDelta, I return false; } + private void processCredentialsCommonAdd(PrismObject focus, + LensContext context, ItemPath credentialsPath, + PrismContainerValue cVal, XMLGregorianCalendar now, Task task, + OperationResult result) + throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { - private void processCredentialsCommonAdd(LensContext context, ItemPath credentialsPath, - PrismContainerValue cVal, XMLGregorianCalendar now, Task task, OperationResult result) - throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { - if (hasValueChange(cVal) && !hasMetadata(cVal)) { + if (hasValueChange(cVal) && !hasMetadata(cVal)) { MetadataType metadataType = LensUtil.createCreateMetadata(context, now, task); - ContainerDelta metadataDelta = ContainerDelta.createModificationAdd(credentialsPath.subPath(AbstractCredentialType.F_METADATA), - UserType.class, prismContext, metadataType); + ContainerDelta metadataDelta = ContainerDelta.createModificationAdd( + credentialsPath.subPath(AbstractCredentialType.F_METADATA), UserType.class, prismContext, + metadataType); context.getFocusContext().swallowToSecondaryDelta(metadataDelta); + } - } + } + + private void processPasswordHistoryDeltas(PrismObject focus, + LensContext context, XMLGregorianCalendar now, Task task, OperationResult result) + throws SchemaException { + if (focus.getCompileTimeClass().equals(UserType.class)) { + PrismContainer password = focus + .findOrCreateContainer(new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_PASSWORD)); + if (password == null || password.isEmpty()) { + return; + } + PrismContainer historyEntries = password + .findOrCreateContainer(PasswordType.F_HISTORY_ENTRY); + + List historyEntryValues = getSortedHistoryList(historyEntries); + createDeleteHistoryDeltasIfNeeded(historyEntryValues, context, task, result); + createAddHistoryDelta(context, password, now); + + } + + } + + private void createAddHistoryDelta(LensContext context, + PrismContainer password, XMLGregorianCalendar now) throws SchemaException { + PrismContainerValue passwordValue = password.getValue(); + PasswordType passwordRealValue = passwordValue.asContainerable(); + + PrismContainerDefinition historyEntryDefinition = password.getDefinition().findContainerDefinition(PasswordType.F_HISTORY_ENTRY); + PrismContainer historyEntry = historyEntryDefinition.instantiate(); + + PrismContainerValue hisotryEntryValue = historyEntry.createNewValue(); + + PasswordHistoryEntryType entryType = hisotryEntryValue.asContainerable(); + entryType.setValue(passwordRealValue.getValue()); + entryType.setMetadata(passwordRealValue.getMetadata()); + entryType.setChangeTimestamp(now); + + ContainerDelta addHisotryDelta = ContainerDelta + .createModificationAdd(new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_PASSWORD, PasswordType.F_HISTORY_ENTRY), UserType.class, prismContext, entryType.clone()); + context.getFocusContext().swallowToSecondaryDelta(addHisotryDelta); + + } + + private void createDeleteHistoryDeltasIfNeeded( + List historyEntryValues, LensContext context, Task task, + OperationResult result) throws SchemaException { + + int maxPasswordsToSave = getMaxPasswordsToSave(context.getFocusContext(), context, task, result); + + int numberOfHistoryEntriesToDelete = historyEntryValues.size() - maxPasswordsToSave; + + if (numberOfHistoryEntriesToDelete >= 0) { + for (int i = 0; i < numberOfHistoryEntriesToDelete; i++) { + ContainerDelta deleteHistoryDelta = ContainerDelta + .createModificationDelete( + new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_PASSWORD, + PasswordType.F_HISTORY_ENTRY), + UserType.class, prismContext, + historyEntryValues.get(i).clone()); + context.getFocusContext().swallowToSecondaryDelta(deleteHistoryDelta); + } + } + + } + + private List getSortedHistoryList( + PrismContainer historyEntries) { + if (historyEntries.isEmpty()) { + return new ArrayList(); + } + List historyEntryValues = PrismContainerValue + .fromPcvList(historyEntries.getValues()); + + Collections.sort(historyEntryValues, new Comparator() { + + @Override + public int compare(PasswordHistoryEntryType o1, PasswordHistoryEntryType o2) { + XMLGregorianCalendar changeTimestampFirst = o1.getChangeTimestamp(); + XMLGregorianCalendar changeTimestampSecond = o2.getChangeTimestamp(); + + return changeTimestampFirst.compare(changeTimestampSecond); + } + }); + return historyEntryValues; + } private boolean hasValueChange(PrismContainerValue cVal) { - for (Item item: cVal.getItems()) { + for (Item item : cVal.getItems()) { QName itemName = item.getElementName(); if (isValueElement(itemName)) { - return true; - } + return true; + } } return false; } - + private boolean isValueElement(QName itemName) { - return !itemName.equals(AbstractCredentialType.F_FAILED_LOGINS) && - !itemName.equals(AbstractCredentialType.F_LAST_FAILED_LOGIN) && - !itemName.equals(AbstractCredentialType.F_LAST_SUCCESSFUL_LOGIN) && - !itemName.equals(AbstractCredentialType.F_METADATA) && - !itemName.equals(AbstractCredentialType.F_PREVIOUS_SUCCESSFUL_LOGIN); + return !itemName.equals(AbstractCredentialType.F_FAILED_LOGINS) + && !itemName.equals(AbstractCredentialType.F_LAST_FAILED_LOGIN) + && !itemName.equals(AbstractCredentialType.F_LAST_SUCCESSFUL_LOGIN) + && !itemName.equals(AbstractCredentialType.F_METADATA) + && !itemName.equals(AbstractCredentialType.F_PREVIOUS_SUCCESSFUL_LOGIN); } private boolean hasMetadata(PrismContainerValue cVal) { - for (Item item: cVal.getItems()) { + for (Item item : cVal.getItems()) { QName itemName = item.getElementName(); - if (itemName.equals(AbstractCredentialType.F_METADATA)) { - return true; - } + if (itemName.equals(AbstractCredentialType.F_METADATA)) { + return true; + } } return false; } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java index 6c13c0ea66c..440674079f5 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java @@ -176,7 +176,7 @@ private boolean wasExecuted(ObjectDelta userDelt } //TODO: maybe some caching of orgs????? - private ValuePolicyType determineValuePolicy(ObjectDelta userDelta, PrismObject object, LensContext context, Task task, OperationResult result) throws SchemaException{ + protected ValuePolicyType determineValuePolicy(ObjectDelta userDelta, PrismObject object, LensContext context, Task task, OperationResult result) throws SchemaException{ //check the modification of organization first ValuePolicyType valuePolicy = determineValuePolicy(userDelta, task, result); @@ -197,7 +197,7 @@ private ValuePolicyType determineVa return valuePolicy; } - private ValuePolicyType determineValuePolicy(ObjectDelta userDelta, Task task, OperationResult result) + protected ValuePolicyType determineValuePolicy(ObjectDelta userDelta, Task task, OperationResult result) throws SchemaException { ReferenceDelta orgDelta = userDelta.findReferenceModification(UserType.F_PARENT_ORG_REF);