diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerWrapper.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerWrapper.java index 622c6095055..4cb633faf66 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerWrapper.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ContainerWrapper.java @@ -109,7 +109,7 @@ public PrismContainerDefinition getItemDefinition() { return container.getDefinition(); } - public ContainerStatus getStatus() { + public ContainerStatus getStatus() { return status; } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ItemWrapper.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ItemWrapper.java index 1bae8a7512b..c47a7c734b6 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ItemWrapper.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ItemWrapper.java @@ -27,6 +27,7 @@ import com.evolveum.midpoint.prism.Revivable; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.util.DebugDumpable; +import org.jetbrains.annotations.Nullable; /** * @author lazyman @@ -90,7 +91,8 @@ default boolean isEnforceRequiredFields() { ContainerWrapper cw = getParent(); return cw == null || cw.isEnforceRequiredFields(); } - + + @Nullable ContainerWrapper getParent(); boolean isShowEmpty(); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PropertyOrReferenceWrapper.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PropertyOrReferenceWrapper.java index 115204a5736..92876dc5ff6 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PropertyOrReferenceWrapper.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PropertyOrReferenceWrapper.java @@ -41,7 +41,7 @@ public abstract class PropertyOrReferenceWrapper values; @@ -83,8 +83,9 @@ public ID getItemDefinition() { } @Override + @Nullable public ContainerWrapper getParent() { - return container.getContainer(); + return container != null ? container.getContainer() : null; } public boolean isVisible() { @@ -96,7 +97,10 @@ public boolean isVisible() { if (getItemDefinition().isDeprecated() && isEmpty()) { return false; } - + + if (container == null) { + return false; // TODO: ok ? + } switch (container.getObjectStatus()) { case ADDING : return canAddDefault() || canAddAndShowEmpty(); @@ -204,7 +208,15 @@ public boolean hasChanged() { return false; } private boolean isMetadataContainer() { - return getParent().getItemDefinition().getTypeName().equals(MetadataType.COMPLEX_TYPE); + ContainerWrapper parent = getParent(); + if (parent == null) { + return false; + } + ItemDefinition definition = parent.getItemDefinition(); + if (definition == null) { + return false; + } + return definition.getTypeName().equals(MetadataType.COMPLEX_TYPE); } @Override diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PropertyWrapper.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PropertyWrapper.java index 55e324fcdbb..4c4849ebac5 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PropertyWrapper.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PropertyWrapper.java @@ -23,9 +23,6 @@ import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.PrettyPrinter; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import org.jetbrains.annotations.Nullable; import java.io.Serializable; @@ -77,13 +74,13 @@ public ValueWrapper createAddedValue() { ValueWrapper wrapper; if (SchemaConstants.T_POLY_STRING_TYPE.equals(definition.getTypeName())) { - wrapper = new ValueWrapper(this, new PrismPropertyValue(new PolyString("")), - new PrismPropertyValue(new PolyString("")), ValueStatus.ADDED); + wrapper = new ValueWrapper(this, new PrismPropertyValue<>(new PolyString("")), + new PrismPropertyValue<>(new PolyString("")), ValueStatus.ADDED); // } else if (isUser() && isThisPropertyActivationEnabled()) { // wrapper = new ValueWrapper(this, new PrismPropertyValue(null), // new PrismPropertyValue(null), ValueStatus.ADDED); } else { - wrapper = new ValueWrapper(this, new PrismPropertyValue(null), ValueStatus.ADDED); + wrapper = new ValueWrapper(this, new PrismPropertyValue<>(null), ValueStatus.ADDED); } return wrapper; @@ -102,22 +99,22 @@ public ValueWrapper createAddedValue() { // return UserType.class.isAssignableFrom(object.getCompileTimeClass()); // } - private boolean isThisPropertyActivationEnabled() { - if (!new ItemPath(UserType.F_ACTIVATION).equivalent(container.getPath())) { - return false; - } - - if (!ActivationType.F_ADMINISTRATIVE_STATUS.equals(item.getElementName())) { - return false; - } - -// if (container.getContainer().getObject() == null || ContainerStatus.MODIFYING.equals(container.getContainer().getObject().getStatus())) { -// //when modifying then we don't want to create "true" value for c:activation/c:enabled, only during add +// private boolean isThisPropertyActivationEnabled() { +// if (!new ItemPath(UserType.F_ACTIVATION).equivalent(container.getPath())) { // return false; // } - - return true; - } +// +// if (!ActivationType.F_ADMINISTRATIVE_STATUS.equals(item.getElementName())) { +// return false; +// } +// +//// if (container.getContainer().getObject() == null || ContainerStatus.MODIFYING.equals(container.getContainer().getObject().getStatus())) { +//// //when modifying then we don't want to create "true" value for c:activation/c:enabled, only during add +//// return false; +//// } +// +// return true; +// } @Override public String toString() { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ReferenceWrapper.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ReferenceWrapper.java index 93e5e9841df..44cee963aaf 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ReferenceWrapper.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ReferenceWrapper.java @@ -22,7 +22,7 @@ import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.PrettyPrinter; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; +import org.jetbrains.annotations.Nullable; import java.io.Serializable; import java.util.ArrayList; @@ -38,11 +38,11 @@ public class ReferenceWrapper extends PropertyOrReferenceWrapper targetTypes; - public ReferenceWrapper(ContainerValueWrapper container, PrismReference reference, boolean readonly, ValueStatus status) { + public ReferenceWrapper(@Nullable ContainerValueWrapper container, PrismReference reference, boolean readonly, ValueStatus status) { super(container, reference, readonly, status, null); } - public ReferenceWrapper(ContainerValueWrapper container, PrismReference reference, boolean readonly, ValueStatus status, ItemPath path) { + public ReferenceWrapper(@Nullable ContainerValueWrapper container, PrismReference reference, boolean readonly, ValueStatus status, ItemPath path) { super(container, reference, readonly, status, path); } @@ -54,7 +54,7 @@ public List getValues() { } private List createValues() { - List values = new ArrayList(); + List values = new ArrayList<>(); for (PrismReferenceValue prismValue : item.getValues()) { @@ -84,8 +84,7 @@ public List getTargetTypes() { @Override public ValueWrapper createAddedValue() { PrismReferenceValue prv = new PrismReferenceValue(); - ValueWrapper wrapper = new ValueWrapper(this, prv, ValueStatus.ADDED); - return wrapper; + return new ValueWrapper(this, prv, ValueStatus.ADDED); } public ObjectFilter getFilter() { diff --git a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/CompositeRefinedObjectClassDefinitionImpl.java b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/CompositeRefinedObjectClassDefinitionImpl.java index ce19c21779e..9dd8284fc71 100644 --- a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/CompositeRefinedObjectClassDefinitionImpl.java +++ b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/CompositeRefinedObjectClassDefinitionImpl.java @@ -38,6 +38,7 @@ import javax.xml.namespace.QName; import java.util.*; import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -585,10 +586,25 @@ public Collection getNamesOfAttributesWithInboundExpressions() } @Override - public ResourcePasswordDefinitionType getPasswordDefinition() { // TODO what if there is a conflict? - return getRefinedObjectClassDefinitionsStream() - .map(def -> def.getPasswordDefinition()) - .findFirst().orElse(null); + public ResourcePasswordDefinitionType getPasswordDefinition() { + return findInDefinitions(def -> def.getPasswordDefinition()); + } + + private T findInDefinitions(Function transform) { + if (structuralObjectClassDefinition != null) { + T val = transform.apply(structuralObjectClassDefinition); + if (val != null) { + return val; + } + } + // TODO what if there is a conflict? + for (RefinedObjectClassDefinition auxiliaryObjectClassDefinition: auxiliaryObjectClassDefinitions) { + T val = transform.apply(auxiliaryObjectClassDefinition); + if (val != null) { + return val; + } + } + return null; } @Override diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd index c48b28d1daf..6bd4ec3bfb1 100755 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd @@ -5840,6 +5840,60 @@ + + + + The way how an resource password is compared with the current password. + + + + 3.7.1 + + + + + + + Auto-detect comparison method. If no way of comparison + is possible then an error is indicated. + Note: Currently this strategy will end with an error if there + is no cached password value. + + + + + + + + + + There is no way to compare password. Any operation to that + tries to compare the password on the resource should end + up with an error. + + + + + + + + + + Compare password with the value cached in the shadow. + This setting assumes that passwords for all accounts are + properly cached. Therefore if there is no password value + in the shadow then we assume that there is no resource password. + + + + + + + + + + + @@ -5860,6 +5914,19 @@ + + + + The way how an resource password is compared with the current password. + This strategy is used when midPoint needs to compare candidate password + with existing resource passowrd. E.g. used in password policies that state + that passwords on several resources cannot be the same. + + + 3.7.1 + + + @@ -5887,6 +5954,23 @@ + + + + Password caching policy. + Currently, password storage format (encrypted, hashed) will be the same + as the global password storage format used for the entire system. + Definition of a specific password storage format might be added later. + + + 3.7.1 + + + + @@ -12009,6 +12093,16 @@ + + + + Specifies which projection should be used in case that projection origin is selected. + + + 3.7.1 + + + @@ -12063,6 +12157,23 @@ + + + + One of object's projecion is the origin. + E.g. in case of user password specific projection + linked to the user will be scanned. + If this origin type is selected then also + the projectionDiscriminator must be specified. + Note: Currently the only supported value is + resource password. + + + + 3.7.1 + + + diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpressionFactory.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpressionFactory.java index 164d3ab7e7f..97077675f05 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpressionFactory.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpressionFactory.java @@ -94,7 +94,8 @@ public ScriptExpression createScriptExpression(ScriptExpressionEvaluatorType exp expression.setOutputDefinition(outputDefinition); expression.setObjectResolver(objectResolver); expression.setFunctions(new ArrayList<>(functions)); - + + // TODO make this code synchronized and ensure that searchIterative below is executed under privileged account if (customFunctionLibraryCache != null) { expression.getFunctions().addAll(customFunctionLibraryCache.values()); } else { diff --git a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java index cbe3679a5f7..aefd254d2dc 100644 --- a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java +++ b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java @@ -527,142 +527,6 @@ protected void assertAdministrativeStatus(PrismObject obje assert status == expected : "status property is "+status+", expected "+expected+" in "+object; } - protected ObjectDelta createModifyUserReplaceDelta(String userOid, QName propertyName, Object... newRealValue) { - return createModifyUserReplaceDelta(userOid, new ItemPath(propertyName), newRealValue); - } - - protected ObjectDelta createModifyUserReplaceDelta(String userOid, ItemPath propertyName, Object... newRealValue) { - return ObjectDelta.createModificationReplaceProperty(UserType.class, userOid, propertyName, prismContext, newRealValue); - } - - protected ObjectDelta createModifyUserAddDelta(String userOid, ItemPath propertyName, Object... newRealValue) { - return ObjectDelta.createModificationAddProperty(UserType.class, userOid, propertyName, prismContext, newRealValue); - } - - protected ObjectDelta createModifyUserDeleteDelta(String userOid, ItemPath propertyName, Object... newRealValue) { - return ObjectDelta.createModificationDeleteProperty(UserType.class, userOid, propertyName, prismContext, newRealValue); - } - - protected ObjectDelta createModifyUserAddAccount(String userOid, PrismObject resource) throws SchemaException { - PrismObject account = getAccountShadowDefinition().instantiate(); - ObjectReferenceType resourceRef = new ObjectReferenceType(); - resourceRef.setOid(resource.getOid()); - account.asObjectable().setResourceRef(resourceRef); - RefinedResourceSchema refinedSchema = RefinedResourceSchemaImpl.getRefinedSchema(resource); - account.asObjectable().setObjectClass(refinedSchema.getDefaultRefinedDefinition(ShadowKindType.ACCOUNT).getObjectClassDefinition().getTypeName()); - - ObjectDelta userDelta = ObjectDelta.createEmptyModifyDelta(UserType.class, userOid, prismContext); - PrismReferenceValue accountRefVal = new PrismReferenceValue(); - accountRefVal.setObject(account); - ReferenceDelta accountDelta = ReferenceDelta.createModificationAdd(UserType.F_LINK_REF, getUserDefinition(), accountRefVal); - userDelta.addModification(accountDelta); - - return userDelta; - } - - protected ObjectDelta createModifyUserDeleteAccount(String userOid, PrismObject resource) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - String accountOid = getLinkRefOid(userOid, resource.getOid()); - PrismObject account = getShadowModel(accountOid); - - ObjectDelta userDelta = ObjectDelta.createEmptyModifyDelta(UserType.class, userOid, prismContext); - PrismReferenceValue accountRefVal = new PrismReferenceValue(); - accountRefVal.setObject(account); - ReferenceDelta accountDelta = ReferenceDelta.createModificationDelete(UserType.F_LINK_REF, getUserDefinition(), accountRefVal); - userDelta.addModification(accountDelta); - - return userDelta; - } - - protected ObjectDelta createModifyUserUnlinkAccount(String userOid, PrismObject resource) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - String accountOid = getLinkRefOid(userOid, resource.getOid()); - - ObjectDelta userDelta = ObjectDelta.createEmptyModifyDelta(UserType.class, userOid, prismContext); - PrismReferenceValue accountRefVal = new PrismReferenceValue(); - accountRefVal.setOid(accountOid); - ReferenceDelta accountDelta = ReferenceDelta.createModificationDelete(UserType.F_LINK_REF, getUserDefinition(), accountRefVal); - userDelta.addModification(accountDelta); - - return userDelta; - } - - protected ObjectDelta createModifyAccountShadowEmptyDelta(String accountOid) { - return ObjectDelta.createEmptyModifyDelta(ShadowType.class, accountOid, prismContext); - } - - protected ObjectDelta createModifyAccountShadowReplaceAttributeDelta(String accountOid, - PrismObject resource, String attributeName, Object... newRealValue) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException { - return createModifyAccountShadowReplaceAttributeDelta(accountOid, resource, getAttributeQName(resource, attributeName), newRealValue); - } - - protected ObjectDelta createModifyAccountShadowReplaceAttributeDelta(String accountOid, - PrismObject resource, QName attributeName, Object... newRealValue) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException { - return createModifyAccountShadowReplaceDelta(accountOid, resource, new ItemPath(ShadowType.F_ATTRIBUTES, attributeName), newRealValue); - } - - protected ObjectDelta createModifyAccountShadowReplaceDelta(String accountOid, PrismObject resource, ItemPath itemPath, Object... newRealValue) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException { - if (ShadowType.F_ATTRIBUTES.equals(ItemPath.getName(itemPath.first()))) { - PropertyDelta attributeDelta = createAttributeReplaceDelta(resource, ((NameItemPathSegment)itemPath.last()).getName(), newRealValue); - ObjectDelta accountDelta = ObjectDelta.createModifyDelta(accountOid, attributeDelta, ShadowType.class, prismContext); - return accountDelta; - } else { - ObjectDelta accountDelta = ObjectDelta.createModificationReplaceProperty( - ShadowType.class, accountOid, itemPath, prismContext, newRealValue); - return accountDelta; - } - } - - protected PropertyDelta createAttributeReplaceDelta(PrismObject resource, String attributeLocalName, T... newRealValue) throws SchemaException { - return createAttributeReplaceDelta(resource, getAttributeQName(resource, attributeLocalName), newRealValue); - } - - protected PropertyDelta createAttributeReplaceDelta(PrismObject resource, QName attributeQName, T... newRealValue) throws SchemaException { - PrismPropertyDefinition attributeDefinition = getAttributeDefinition(resource, attributeQName); - if (attributeDefinition == null) { - throw new SchemaException("No definition for attribute "+ attributeQName+ " in " + resource); - } - return PropertyDelta.createModificationReplaceProperty(new ItemPath(ShadowType.F_ATTRIBUTES, attributeQName), - attributeDefinition, newRealValue); - } - - protected PropertyDelta createAttributeAddDelta(PrismObject resource, String attributeLocalName, T... newRealValue) throws SchemaException { - return createAttributeAddDelta(resource, getAttributeQName(resource, attributeLocalName), newRealValue); - } - - protected PropertyDelta createAttributeAddDelta(PrismObject resource, QName attributeQName, T... newRealValue) throws SchemaException { - PrismPropertyDefinition attributeDefinition = getAttributeDefinition(resource, attributeQName); - if (attributeDefinition == null) { - throw new SchemaException("No definition for attribute "+ attributeQName+ " in " + resource); - } - return PropertyDelta.createModificationAddProperty(new ItemPath(ShadowType.F_ATTRIBUTES, attributeQName), - attributeDefinition, newRealValue); - } - - protected PropertyDelta createAttributeDeleteDelta(PrismObject resource, String attributeLocalName, T... newRealValue) throws SchemaException { - return createAttributeDeleteDelta(resource, getAttributeQName(resource, attributeLocalName), newRealValue); - } - - protected PropertyDelta createAttributeDeleteDelta(PrismObject resource, QName attributeQName, T... newRealValue) throws SchemaException { - PrismPropertyDefinition attributeDefinition = getAttributeDefinition(resource, attributeQName); - if (attributeDefinition == null) { - throw new SchemaException("No definition for attribute "+ attributeQName+ " in " + resource); - } - return PropertyDelta.createModificationDeleteProperty(new ItemPath(ShadowType.F_ATTRIBUTES, attributeQName), - attributeDefinition, newRealValue); - } - - protected ResourceAttributeDefinition getAttributeDefinition(PrismObject resource, QName attributeName) throws SchemaException { - RefinedResourceSchema refinedSchema = RefinedResourceSchemaImpl.getRefinedSchema(resource); - if (refinedSchema == null) { - throw new SchemaException("No refined schema for "+resource); - } - RefinedObjectClassDefinition accountDefinition = refinedSchema.getDefaultRefinedDefinition(ShadowKindType.ACCOUNT); - return accountDefinition.findAttributeDefinition(attributeName); - } - - protected ObjectDelta createModifyAccountShadowAddDelta(String accountOid, ItemPath propertyName, Object... newRealValue) { - return ObjectDelta.createModificationAddProperty(ShadowType.class, accountOid, propertyName, prismContext, newRealValue); - } - protected void modifyUserReplace(String userOid, QName propertyName, Task task, OperationResult result, Object... newRealValue) throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException, CommunicationException, ConfigurationException, ObjectAlreadyExistsException, PolicyViolationException, SecurityViolationException { @@ -2650,16 +2514,51 @@ protected void assertShadowModel(PrismObject accountShadow, String o assertShadowCommon(accountShadow, oid, username, resourceType, objectClass, nameMatchingRule, false); IntegrationTestTools.assertProvisioningShadow(accountShadow, resourceType, RefinedAttributeDefinition.class, objectClass); } + + + protected ObjectDelta createModifyUserAddAccount(String userOid, PrismObject resource) throws SchemaException { + PrismObject account = getAccountShadowDefinition().instantiate(); + ObjectReferenceType resourceRef = new ObjectReferenceType(); + resourceRef.setOid(resource.getOid()); + account.asObjectable().setResourceRef(resourceRef); + RefinedResourceSchema refinedSchema = RefinedResourceSchemaImpl.getRefinedSchema(resource); + account.asObjectable().setObjectClass(refinedSchema.getDefaultRefinedDefinition(ShadowKindType.ACCOUNT).getObjectClassDefinition().getTypeName()); + + ObjectDelta userDelta = ObjectDelta.createEmptyModifyDelta(UserType.class, userOid, prismContext); + PrismReferenceValue accountRefVal = new PrismReferenceValue(); + accountRefVal.setObject(account); + ReferenceDelta accountDelta = ReferenceDelta.createModificationAdd(UserType.F_LINK_REF, getUserDefinition(), accountRefVal); + userDelta.addModification(accountDelta); + + return userDelta; + } + + protected ObjectDelta createModifyUserDeleteAccount(String userOid, PrismObject resource) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + String accountOid = getLinkRefOid(userOid, resource.getOid()); + PrismObject account = getShadowModel(accountOid); + + ObjectDelta userDelta = ObjectDelta.createEmptyModifyDelta(UserType.class, userOid, prismContext); + PrismReferenceValue accountRefVal = new PrismReferenceValue(); + accountRefVal.setObject(account); + ReferenceDelta accountDelta = ReferenceDelta.createModificationDelete(UserType.F_LINK_REF, getUserDefinition(), accountRefVal); + userDelta.addModification(accountDelta); - protected QName getAttributeQName(PrismObject resource, String attributeLocalName) { - String resourceNamespace = ResourceTypeUtil.getResourceNamespace(resource); - return new QName(resourceNamespace, attributeLocalName); + return userDelta; } - protected ItemPath getAttributePath(PrismObject resource, String attributeLocalName) { - return new ItemPath(ShadowType.F_ATTRIBUTES, getAttributeQName(resource, attributeLocalName)); + protected ObjectDelta createModifyUserUnlinkAccount(String userOid, PrismObject resource) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + String accountOid = getLinkRefOid(userOid, resource.getOid()); + + ObjectDelta userDelta = ObjectDelta.createEmptyModifyDelta(UserType.class, userOid, prismContext); + PrismReferenceValue accountRefVal = new PrismReferenceValue(); + accountRefVal.setOid(accountOid); + ReferenceDelta accountDelta = ReferenceDelta.createModificationDelete(UserType.F_LINK_REF, getUserDefinition(), accountRefVal); + userDelta.addModification(accountDelta); + + return userDelta; } + // TASKS protected void waitForTaskFinish(Task task, boolean checkSubresult) throws Exception { diff --git a/provisioning/provisioning-api/src/main/java/com/evolveum/midpoint/provisioning/api/ItemComparisonResult.java b/provisioning/provisioning-api/src/main/java/com/evolveum/midpoint/provisioning/api/ItemComparisonResult.java new file mode 100644 index 00000000000..d498218157d --- /dev/null +++ b/provisioning/provisioning-api/src/main/java/com/evolveum/midpoint/provisioning/api/ItemComparisonResult.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010-2018 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.provisioning.api; + +/** + * @author semancik + * + */ +public enum ItemComparisonResult { + + /** + * Value matches. Stored value is different. + */ + MATCH, + + /** + * Value mismatch. Stored value is the same. + */ + MISMATCH, + + /** + * Cannot compare. Comparison is not applicable. + */ + NOT_APPLICABLE + +} diff --git a/provisioning/provisioning-api/src/main/java/com/evolveum/midpoint/provisioning/api/ProvisioningService.java b/provisioning/provisioning-api/src/main/java/com/evolveum/midpoint/provisioning/api/ProvisioningService.java index 7b64985d77f..186ddfa1d89 100644 --- a/provisioning/provisioning-api/src/main/java/com/evolveum/midpoint/provisioning/api/ProvisioningService.java +++ b/provisioning/provisioning-api/src/main/java/com/evolveum/midpoint/provisioning/api/ProvisioningService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Evolveum + * Copyright (c) 2010-2018 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,8 +24,10 @@ import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.prism.Objectable; import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.crypto.EncryptionException; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.query.ObjectPaging; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.schema.GetOperationOptions; @@ -59,7 +61,7 @@ *

* Status: public * Stability: STABLE, only compatible changes are expected - * @version 3.4 + * @version 3.7.1 * @author Radovan Semancik *

*

@@ -73,13 +75,9 @@ * Supported object types: *

    *
  • Resource
  • - *
  • ResourceObjectShadow and all sub-types
  • + *
  • Shadow
  • *
  • Connector
  • *
- * Supported extra data types: - *
    - *
  • Resource Objects (Resource Schema)
  • - *
*

*

* TODO: better documentation @@ -502,6 +500,15 @@ ConstraintsCheckingResult checkConstraints(RefinedObjectClassDefinition shadowDe void enterConstraintsCheckerCache(); void exitConstraintsCheckerCache(); + + /** + * Compare value on the resource with the provided value. This method is used to compare resource attributes + * or passwords, e.g. for the purposes of password policy. + * Note: comparison may be quite an expensive and heavy weight operation, e.g. it may try authenticating the user + * on the resource. + */ + ItemComparisonResult compare(Class type, String oid, ItemPath path, T expectedValue, Task task, OperationResult result) + throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException, EncryptionException; void shutdown(); diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ErrorHandlerFactory.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ErrorHandlerFactory.java index 05cb5bff605..3fd0bb32013 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ErrorHandlerFactory.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/consistency/impl/ErrorHandlerFactory.java @@ -63,7 +63,7 @@ public class ErrorHandlerFactory { - public ErrorHandler createErrorHandler(Exception ex){ + public ErrorHandler createErrorHandler(Throwable ex) { if (ex instanceof CommunicationException){ return communicationExceptionHandler; } @@ -85,6 +85,12 @@ public ErrorHandler createErrorHandler(Exception ex){ if (ex instanceof SecurityViolationException){ return securityViolationHandler; } + if (ex instanceof RuntimeException) { + throw (RuntimeException)ex; + } + if (ex instanceof Error) { + throw (Error)ex; + } throw new SystemException(ex != null ? ex.getClass().getName() +": "+ ex.getMessage() : "Unexpected error:", ex); } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ProvisioningServiceImpl.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ProvisioningServiceImpl.java index f0bd2560388..f3da89e65d0 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ProvisioningServiceImpl.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ProvisioningServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Evolveum + * Copyright (c) 2010-2018 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,9 +36,10 @@ import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.PrismProperty; +import com.evolveum.midpoint.prism.crypto.EncryptionException; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.prism.delta.PropertyDelta; +import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.query.NoneFilter; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectPaging; @@ -46,6 +47,7 @@ import com.evolveum.midpoint.provisioning.api.ConstraintViolationConfirmer; import com.evolveum.midpoint.provisioning.api.ConstraintsCheckingResult; import com.evolveum.midpoint.provisioning.api.GenericConnectorException; +import com.evolveum.midpoint.provisioning.api.ItemComparisonResult; import com.evolveum.midpoint.provisioning.api.ProvisioningOperationOptions; import com.evolveum.midpoint.provisioning.api.ProvisioningService; import com.evolveum.midpoint.provisioning.impl.ShadowCacheFactory.Mode; @@ -68,7 +70,6 @@ import com.evolveum.midpoint.schema.statistics.ConnectorOperationalStatus; import com.evolveum.midpoint.schema.util.ObjectQueryUtil; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; -import com.evolveum.midpoint.schema.util.ResourceTypeUtil; import com.evolveum.midpoint.schema.util.SchemaDebugUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.DebugUtil; @@ -82,7 +83,6 @@ import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.xml.ns._public.common.common_3.CachingMetadataType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorHostType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType; import com.evolveum.midpoint.xml.ns._public.common.common_3.FailedOperationTypeType; @@ -91,7 +91,6 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ProvisioningScriptType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowCheckType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; /** @@ -247,23 +246,10 @@ public PrismObject getObject(Class type, String oid result.computeStatus(); } throw e; - } catch (CommunicationException e) { + } catch (CommunicationException | SchemaException | ConfigurationException | SecurityViolationException | RuntimeException | Error e) { ProvisioningUtil.recordFatalError(LOGGER, result, "Error getting object OID=" + oid + ": " + e.getMessage(), e); throw e; - } catch (SchemaException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Error getting object OID=" + oid + ": " + e.getMessage(), e); - throw e; - } catch (ConfigurationException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Error getting object OID=" + oid + ": " + e.getMessage(), e); - throw e; - } catch (SecurityViolationException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Error getting object OID=" + oid + ": " + e.getMessage(), e); - throw e; - } catch (SystemException e) { - // Do NOT wrap this into SystemException again - ProvisioningUtil.recordFatalError(LOGGER, result, "Error getting object OID=" + oid + ": " + e.getMessage(), e); - throw e; - } catch (RuntimeException e){ + } catch (EncryptionException e){ ProvisioningUtil.recordFatalError(LOGGER, result, "Error getting object OID=" + oid + ": " + e.getMessage(), e); throw new SystemException(e); } @@ -335,6 +321,9 @@ public String addObject(PrismObject object, OperationP } catch (ExpressionEvaluationException ex) { ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't add object. Expression error: " + ex.getMessage(), ex); throw ex; + } catch (EncryptionException e) { + ProvisioningUtil.recordFatalError(LOGGER, result, null, e); + throw new SystemException(e.getMessage(), e); } catch (RuntimeException | Error ex){ ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't add object. Runtime error: " + ex.getMessage(), ex); throw ex; @@ -386,34 +375,16 @@ public int synchronize(ResourceShadowDiscriminator shadowCoordinates, Task task, processedChanges = getShadowCache(Mode.STANDARD).synchronize(shadowCoordinates, tokenProperty, task, result); LOGGER.debug("Synchronization of {} done, token {}, {} changes", resource, tokenProperty, processedChanges); - } catch (ObjectNotFoundException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: object not found: " + e.getMessage(), e); - throw e; - } catch (CommunicationException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: communication problem: " + e.getMessage(), e); + } catch (ObjectNotFoundException | CommunicationException | SchemaException | SecurityViolationException | ConfigurationException | ExpressionEvaluationException | RuntimeException | Error e) { + ProvisioningUtil.recordFatalError(LOGGER, result, null, e); throw e; - } catch (ObjectAlreadyExistsException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: object already exists problem: " + e.getMessage(), e); + } catch (ObjectAlreadyExistsException | EncryptionException e) { + ProvisioningUtil.recordFatalError(LOGGER, result, null, e); throw new SystemException(e); } catch (GenericFrameworkException e) { ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: generic connector framework error: " + e.getMessage(), e); throw new GenericConnectorException(e.getMessage(), e); - } catch (SchemaException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: schema problem: " + e.getMessage(), e); - throw e; - } catch (SecurityViolationException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: security violation: " + e.getMessage(), e); - throw e; - } catch (ConfigurationException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: configuration problem: " + e.getMessage(), e); - throw e; - } catch (RuntimeException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: unexpected problem: " + e.getMessage(), e); - throw e; - } catch (ExpressionEvaluationException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: expression error: " + e.getMessage(), e); - throw e; } result.recordSuccess(); @@ -678,34 +649,19 @@ public String modifyObject(Class type, String oid, result.computeStatus(); } - } catch (CommunicationException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't modify object: communication problem: " + e.getMessage(), e); + } catch (CommunicationException | SchemaException | ObjectNotFoundException | ConfigurationException | SecurityViolationException + | ExpressionEvaluationException | RuntimeException | Error e) { + ProvisioningUtil.recordFatalError(LOGGER, result, null, e); throw e; } catch (GenericFrameworkException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't modify object: generic error in the connector: " + e.getMessage(), - e); + ProvisioningUtil.recordFatalError(LOGGER, result, null, e); throw new CommunicationException(e.getMessage(), e); - } catch (SchemaException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't modify object: schema problem: " + e.getMessage(), e); - throw e; - } catch (ObjectNotFoundException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't modify object: object doesn't exist: " + e.getMessage(), e); - throw e; - } catch (RuntimeException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't modify object: unexpected problem: " + e.getMessage(), e); - throw new SystemException("Internal error: " + e.getMessage(), e); - } catch (ConfigurationException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't modify object: configuration problem: " + e.getMessage(), e); - throw e; - } catch (SecurityViolationException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't modify object: security violation: " + e.getMessage(), e); - throw e; + } catch (EncryptionException e) { + ProvisioningUtil.recordFatalError(LOGGER, result, null, e); + throw new SystemException(e.getMessage(), e); } catch (ObjectAlreadyExistsException e) { ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't modify object: object after modification would conflict with another existing object: " + e.getMessage(), e); throw e; - } catch (ExpressionEvaluationException e) { - ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't modify object: expression errror: " + e.getMessage(), e); - throw e; } result.cleanupResult(); @@ -758,9 +714,9 @@ public void deleteObject(Class type, String oid, Provi } catch (ExpressionEvaluationException e) { ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't delete object: expression errror: " + e.getMessage(), e); throw e; - } catch (RuntimeException e){ + } catch (RuntimeException | Error e) { ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't delete object: " + e.getMessage(), e); - throw new SystemException(e); + throw e; } } else if (object.canRepresent(ResourceType.class)) { @@ -923,6 +879,10 @@ public void refreshShadow(PrismObject shadow, ProvisioningOperationO | SecurityViolationException | ObjectAlreadyExistsException | ExpressionEvaluationException | RuntimeException | Error e) { ProvisioningUtil.recordFatalError(LOGGER, result, "Couldn't refresh shadow: " + e.getClass().getSimpleName() + ": "+ e.getMessage(), e); throw e; + + } catch (EncryptionException e) { + ProvisioningUtil.recordFatalError(LOGGER, result, null, e); + throw new SystemException(e.getMessage(), e); } result.computeStatus(); @@ -933,7 +893,7 @@ public void refreshShadow(PrismObject shadow, ProvisioningOperationO private void refreshShadowLegacy(PrismObject shadow, ProvisioningOperationOptions options, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, - ObjectAlreadyExistsException, SecurityViolationException, GenericFrameworkException, ExpressionEvaluationException { + ObjectAlreadyExistsException, SecurityViolationException, GenericFrameworkException, ExpressionEvaluationException, EncryptionException { ShadowType shadowType = shadow.asObjectable(); @@ -1344,4 +1304,42 @@ private PrismObject getRepoObject(Class type, Strin } } + @Override + public ItemComparisonResult compare(Class type, String oid, ItemPath path, + T expectedValue, Task task, OperationResult parentResult) + throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException, EncryptionException { + Validate.notNull(oid, "Oid of object to get must not be null."); + Validate.notNull(parentResult, "Operation result must not be null."); + + if (!ShadowType.class.isAssignableFrom(type)) { + throw new UnsupportedOperationException("Only shadow compare is supported"); + } + + // Result type for this operation + OperationResult result = parentResult.createMinorSubresult(ProvisioningService.class.getName() + ".compare"); + result.addParam(OperationResult.PARAM_OID, oid); + result.addParam(OperationResult.PARAM_TYPE, type); + + ItemComparisonResult comparisonResult; + try { + + PrismObject repositoryObject = getRepoObject(type, oid, null, result); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Retrieved repository object:\n{}", repositoryObject.debugDump()); + } + + comparisonResult = getShadowCache(Mode.STANDARD).compare((PrismObject) (repositoryObject), path, expectedValue, task, result); + + } catch (ObjectNotFoundException | CommunicationException | SchemaException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException | EncryptionException | RuntimeException | Error e) { + ProvisioningUtil.recordFatalError(LOGGER, result, null, e); + throw e; + } + + + result.computeStatus(); + result.cleanupResult(); + + return comparisonResult; + } + } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceEventListenerImpl.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceEventListenerImpl.java index 4b7883efdbc..0d37fe53cf4 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceEventListenerImpl.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceEventListenerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Evolveum + * Copyright (c) 2010-2018 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ //import com.evolveum.midpoint.model.ModelWebService; import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.crypto.EncryptionException; import com.evolveum.midpoint.provisioning.api.ChangeNotificationDispatcher; import com.evolveum.midpoint.provisioning.api.GenericConnectorException; import com.evolveum.midpoint.provisioning.api.ResourceEventDescription; @@ -45,6 +46,7 @@ import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; +import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; @@ -116,10 +118,13 @@ public void notifyEvent(ResourceEventDescription eventDescription, Task task, Op ObjectClassComplexTypeDefinition objectClassDefinition = ShadowUtil.getObjectClassDefinition(shadow); change.setObjectClassDefinition(objectClassDefinition); - ShadowType shadowType = shadow.asObjectable(); - LOGGER.trace("Start to precess change: {}", change.toString()); - shadowCache.processChange(ctx, change, null, parentResult); + try { + shadowCache.processChange(ctx, change, null, parentResult); + } catch (EncryptionException e) { + // TODO: better handling + throw new SystemException(e.getMessage(), e); + } LOGGER.trace("Change after processing {} . Start synchronizing.", change.toString()); shadowCache.processSynchronization(ctx, change, parentResult); diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java index 696cea9f2b0..34d099e78b3 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java @@ -21,6 +21,8 @@ import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.common.refinery.ShadowDiscriminatorObjectDelta; 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.*; import com.evolveum.midpoint.prism.match.MatchingRuleRegistry; import com.evolveum.midpoint.prism.path.IdItemPathSegment; @@ -67,6 +69,7 @@ import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ReadCapabilityType; 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.BooleanUtils; import org.apache.commons.lang.StringUtils; @@ -106,41 +109,19 @@ public abstract class ShadowCache { @Qualifier("cacheRepositoryService") private RepositoryService repositoryService; - @Autowired(required = true) - private ErrorHandlerFactory errorHandlerFactory; - - @Autowired(required = true) - private ResourceManager resourceManager; - - @Autowired(required = true) - private Clock clock; - - @Autowired(required = true) - private PrismContext prismContext; - - @Autowired(required = true) - private ResourceObjectConverter resouceObjectConverter; - - @Autowired(required = true) - private MatchingRuleRegistry matchingRuleRegistry; - - @Autowired(required = true) - protected ShadowManager shadowManager; - - @Autowired(required = true) - private ChangeNotificationDispatcher operationListener; - - @Autowired(required = true) - private AccessChecker accessChecker; - - @Autowired(required = true) - private TaskManager taskManager; - - @Autowired(required = true) - private ChangeNotificationDispatcher changeNotificationDispatcher; - - @Autowired(required = true) - private ProvisioningContextFactory ctxFactory; + @Autowired private ErrorHandlerFactory errorHandlerFactory; + @Autowired private ResourceManager resourceManager; + @Autowired private Clock clock; + @Autowired private PrismContext prismContext; + @Autowired private ResourceObjectConverter resouceObjectConverter; + @Autowired private MatchingRuleRegistry matchingRuleRegistry; + @Autowired protected ShadowManager shadowManager; + @Autowired private ChangeNotificationDispatcher operationListener; + @Autowired private AccessChecker accessChecker; + @Autowired private TaskManager taskManager; + @Autowired private ChangeNotificationDispatcher changeNotificationDispatcher; + @Autowired private ProvisioningContextFactory ctxFactory; + @Autowired private Protector protector; private static final Trace LOGGER = TraceManager.getTrace(ShadowCache.class); @@ -167,7 +148,7 @@ public PrismContext getPrismContext() { public PrismObject getShadow(String oid, PrismObject repositoryShadow, Collection> options, Task task, OperationResult parentResult) throws ObjectNotFoundException, CommunicationException, SchemaException, - ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + ConfigurationException, SecurityViolationException, ExpressionEvaluationException, EncryptionException { Validate.notNull(oid, "Object id must not be null."); @@ -363,7 +344,7 @@ public PrismObject getShadow(String oid, PrismObject rep private PrismObject processNoFetchGet(ProvisioningContext ctx, PrismObject repositoryShadow, Collection> options, OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { ResourceType resource = ctx.getResource(); ShadowType repositoryShadowType = repositoryShadow.asObjectable(); @@ -551,13 +532,13 @@ public abstract String afterAddOnResource( ProvisioningOperationState>> opState, OperationResult parentResult) throws SchemaException, ObjectAlreadyExistsException, - ObjectNotFoundException, ConfigurationException, CommunicationException, ExpressionEvaluationException; + ObjectNotFoundException, ConfigurationException, CommunicationException, ExpressionEvaluationException, EncryptionException; public String addShadow(PrismObject shadowToAdd, OperationProvisioningScriptsType scripts, ResourceType resource, ProvisioningOperationOptions options, Task task, OperationResult parentResult) throws CommunicationException, GenericFrameworkException, ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException, - ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + ConfigurationException, SecurityViolationException, ExpressionEvaluationException, EncryptionException { Validate.notNull(shadowToAdd, "Object to add must not be null."); InternalMonitor.recordCount(InternalCounters.SHADOW_CHANGE_OPERATION_COUNT); @@ -768,7 +749,7 @@ public abstract void afterModifyOnResource( ProvisioningOperationState>>> opState, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ConfigurationException, - CommunicationException, ExpressionEvaluationException; + CommunicationException, ExpressionEvaluationException, EncryptionException; public abstract Collection beforeModifyOnResource(PrismObject shadow, ProvisioningOperationOptions options, Collection modifications) @@ -778,7 +759,7 @@ public String modifyShadow(PrismObject repoShadow, Collection modifications, OperationProvisioningScriptsType scripts, ProvisioningOperationOptions options, Task task, OperationResult parentResult) throws CommunicationException, GenericFrameworkException, ObjectNotFoundException, - SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException, EncryptionException { Validate.notNull(repoShadow, "Object to modify must not be null."); Validate.notNull(modifications, "Object modification must not be null."); @@ -1107,7 +1088,7 @@ private void notifyAfterDelete( } - public PrismObject refreshShadow(PrismObject repoShadow, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + public PrismObject refreshShadow(PrismObject repoShadow, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException { ShadowType shadowType = repoShadow.asObjectable(); List pendingOperations = shadowType.getPendingOperation(); if (pendingOperations.isEmpty()) { @@ -1588,7 +1569,7 @@ public SearchResultMetadata searchObjectsIterative(final ProvisioningContext ctx LOGGER.error("Configuration error: {}", e.getMessage(), e); return false; } catch (ObjectNotFoundException | ObjectAlreadyExistsException | CommunicationException - | SecurityViolationException | GenericConnectorException | ExpressionEvaluationException e) { + | SecurityViolationException | GenericConnectorException | ExpressionEvaluationException | EncryptionException e) { objResult.recordFatalError(e.getMessage(), e); LOGGER.error("{}", e.getMessage(), e); return false; @@ -1803,7 +1784,7 @@ private void validateShadow(PrismObject shadow, boolean requireOid) private PrismObject lookupOrCreateShadowInRepository(ProvisioningContext ctx, PrismObject resourceShadow, boolean unknownIntent, OperationResult parentResult) throws SchemaException, ConfigurationException, ObjectNotFoundException, - CommunicationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException { + CommunicationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException, EncryptionException { PrismObject repoShadow = shadowManager.lookupShadowInRepository(ctx, resourceShadow, parentResult); @@ -1828,7 +1809,7 @@ private PrismObject lookupOrCreateShadowInRepository(ProvisioningCon private PrismObject createShadowInRepository(ProvisioningContext ctx, PrismObject resourceShadow, boolean unknownIntent, OperationResult parentResult) throws SchemaException, ConfigurationException, ObjectNotFoundException, - CommunicationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException { + CommunicationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException, EncryptionException { PrismObject repoShadow; PrismObject conflictingShadow = shadowManager.lookupConflictingShadowBySecondaryIdentifiers(ctx, @@ -2015,7 +1996,7 @@ public boolean handle(PrismObject shadow, OperationResult objResult) public int synchronize(ResourceShadowDiscriminator shadowCoordinates, PrismProperty lastToken, Task task, OperationResult parentResult) throws ObjectNotFoundException, CommunicationException, GenericFrameworkException, SchemaException, ConfigurationException, - SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException { + SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, EncryptionException { InternalMonitor.recordCount(InternalCounters.PROVISIONING_ALL_EXT_OPERATION_COUNT); @@ -2109,7 +2090,7 @@ public int synchronize(ResourceShadowDiscriminator shadowCoordinates, PrismPrope return processedChanges; } catch (SchemaException | CommunicationException | GenericFrameworkException | ConfigurationException | - ObjectNotFoundException | ObjectAlreadyExistsException | ExpressionEvaluationException | RuntimeException | Error ex) { + ObjectNotFoundException | ObjectAlreadyExistsException | ExpressionEvaluationException | EncryptionException | RuntimeException | Error ex) { parentResult.recordFatalError(ex); throw ex; } @@ -2289,7 +2270,7 @@ private void deleteShadowFromRepoIfNeeded(Change change, OperationResult parentR void processChange(ProvisioningContext ctx, Change change, PrismObject oldShadow, OperationResult parentResult) throws SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ObjectNotFoundException, - GenericConnectorException, ObjectAlreadyExistsException, ExpressionEvaluationException { + GenericConnectorException, ObjectAlreadyExistsException, ExpressionEvaluationException, EncryptionException { if (oldShadow == null) { oldShadow = shadowManager.findOrAddShadowFromChange(ctx, change, parentResult); @@ -2518,13 +2499,13 @@ private ProvisioningContext reapplyDefinitions(ProvisioningContext ctx, /** * Make sure that the shadow is complete, e.g. that all the mandatory fields * are filled (e.g name, resourceRef, ...) Also transforms the shadow with - * respect to simulated capabilities. + * respect to simulated capabilities. */ private PrismObject completeShadow(ProvisioningContext ctx, PrismObject resourceShadow, PrismObject repoShadow, OperationResult parentResult) throws SchemaException, ConfigurationException, ObjectNotFoundException, - CommunicationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException { + CommunicationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException, EncryptionException { PrismObject resultShadow = repoShadow.clone(); @@ -2949,7 +2930,7 @@ public void propagateOperations(PrismObject resource, PrismObject< throw new IllegalStateException("Delta from outer space: "+operationDelta); } - // TODO: change operation status, set async references, etc. modify exists/dead flags --- delegate to shadow manager? + // do we need to modify exists/dead flags? } @@ -2961,4 +2942,63 @@ private boolean isPropagationTriggered(PendingOperationType pendingOperation, Du return XmlTypeConverter.isAfterInterval(requestTimestamp, operationGroupingInterval, now); } + public ItemComparisonResult compare(PrismObject repositoryShadow, ItemPath path, T expectedValue, Task task, OperationResult parentResult) + throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException, EncryptionException { + + if (!path.equals(SchemaConstants.PATH_PASSWORD_VALUE)) { + throw new UnsupportedOperationException("Only password comparison is supported"); + } + + ProvisioningContext ctx = ctxFactory.create(repositoryShadow, task, parentResult); + try { + ctx.assertDefinition(); + applyAttributesDefinition(ctx, repositoryShadow); + } catch (ObjectNotFoundException | SchemaException | CommunicationException + | ConfigurationException | ExpressionEvaluationException e) { + throw e; + } + + ResourceType resource = ctx.getResource(); + + PasswordCompareStrategyType passwordCompareStrategy = getPasswordCompareStrategy(ctx.getObjectClassDefinition()); + if (passwordCompareStrategy == PasswordCompareStrategyType.ERROR) { + throw new UnsupportedOperationException("Password comparison is not supported on "+resource); + } + + PrismProperty repoProperty = repositoryShadow.findProperty(path); + if (repoProperty == null) { + if (passwordCompareStrategy == PasswordCompareStrategyType.CACHED) { + if (expectedValue == null) { + return ItemComparisonResult.MATCH; + } else { + return ItemComparisonResult.MISMATCH; + } + } else { + // AUTO + return ItemComparisonResult.NOT_APPLICABLE; + } + } + + ProtectedStringType repoProtectedString = (ProtectedStringType) repoProperty.getRealValue(); + ProtectedStringType expectedProtectedString = new ProtectedStringType(); + if (expectedValue instanceof ProtectedStringType) { + expectedProtectedString = (ProtectedStringType)expectedValue; + } else { + expectedProtectedString = new ProtectedStringType(); + expectedProtectedString.setClearValue((String) expectedValue); + } + if (protector.compare(repoProtectedString, expectedProtectedString)) { + return ItemComparisonResult.MATCH; + } else { + return ItemComparisonResult.MISMATCH; + } + } + + private PasswordCompareStrategyType getPasswordCompareStrategy(RefinedObjectClassDefinition objectClassDefinition) { + ResourcePasswordDefinitionType passwordDefinition = objectClassDefinition.getPasswordDefinition(); + if (passwordDefinition == null) { + return null; + } + return passwordDefinition.getCompareStrategy(); + } } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCacheProvisioner.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCacheProvisioner.java index 81b93e31678..f6eafa2cbfd 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCacheProvisioner.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCacheProvisioner.java @@ -22,6 +22,7 @@ import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismPropertyValue; +import com.evolveum.midpoint.prism.crypto.EncryptionException; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.delta.PropertyDelta; @@ -44,14 +45,14 @@ public class ShadowCacheProvisioner extends ShadowCache { private static final Trace LOGGER = TraceManager.getTrace(ShadowCacheProvisioner.class); - + @Override public String afterAddOnResource( ProvisioningContext ctx, PrismObject shadowToAdd, ProvisioningOperationState>> opState, OperationResult parentResult) - throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException, ConfigurationException, CommunicationException, ExpressionEvaluationException { + throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException, ConfigurationException, CommunicationException, ExpressionEvaluationException, EncryptionException { return shadowManager.addNewActiveRepositoryShadow(ctx, shadowToAdd, opState, parentResult); } @@ -63,7 +64,7 @@ public void afterModifyOnResource( Collection modifications, ProvisioningOperationState>>> opState, OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, ConfigurationException, CommunicationException, ExpressionEvaluationException { + throws SchemaException, ObjectNotFoundException, ConfigurationException, CommunicationException, ExpressionEvaluationException, EncryptionException { shadowManager.modifyShadow(ctx, shadow, modifications, opState, parentResult); } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowManager.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowManager.java index ba298e186ff..fe884872c8a 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowManager.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Evolveum + * Copyright (c) 2010-2018 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,12 +20,10 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.function.Predicate; import javax.xml.namespace.QName; import org.apache.commons.lang.BooleanUtils; -import org.jfree.util.Log; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @@ -47,6 +45,8 @@ import com.evolveum.midpoint.prism.PrismPropertyDefinition; import com.evolveum.midpoint.prism.PrismPropertyValue; import com.evolveum.midpoint.prism.PrismValue; +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.ContainerDelta; import com.evolveum.midpoint.prism.delta.ItemDelta; @@ -70,7 +70,6 @@ import com.evolveum.midpoint.repo.api.ModificationPrecondition; import com.evolveum.midpoint.repo.api.OptimisticLockingRunner; import com.evolveum.midpoint.repo.api.PreconditionViolationException; -import com.evolveum.midpoint.repo.api.RepositoryOperation; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.repo.api.VersionPrecondition; import com.evolveum.midpoint.schema.DeltaConvertor; @@ -83,7 +82,6 @@ import com.evolveum.midpoint.schema.result.AsynchronousOperationResult; import com.evolveum.midpoint.schema.result.AsynchronousOperationReturnValue; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.schema.util.ResourceTypeUtil; @@ -105,6 +103,7 @@ import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CachingMetadataType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CachingPolicyType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CachingStategyType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.FailedOperationTypeType; @@ -115,12 +114,14 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.RecordPendingOperationsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceConsistencyType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectAssociationDirectionType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourcePasswordDefinitionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import com.evolveum.prism.xml.ns._public.types_3.ChangeTypeType; 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; /** * Responsibilities: @@ -143,17 +144,11 @@ public class ShadowManager { @Qualifier("cacheRepositoryService") private RepositoryService repositoryService; - @Autowired(required = true) - private Clock clock; - - @Autowired(required = true) - private PrismContext prismContext; - - @Autowired(required = true) - private TaskManager taskManager; - - @Autowired(required = true) - private MatchingRuleRegistry matchingRuleRegistry; + @Autowired private Clock clock; + @Autowired private PrismContext prismContext; + @Autowired private TaskManager taskManager; + @Autowired private MatchingRuleRegistry matchingRuleRegistry; + @Autowired private Protector protector; private static final Trace LOGGER = TraceManager.getTrace(ShadowManager.class); @@ -207,7 +202,6 @@ public PrismObject lookupShadowInRepository(ProvisioningContext ctx, LOGGER.trace("Searching for shadow using filter:\n{}", query.debugDump()); } -// PagingType paging = new PagingType(); // TODO: check for errors List> results = repositoryService.searchObjects(ShadowType.class, query, null, parentResult); @@ -418,7 +412,7 @@ private List> getNormalizedValue(PrismProperty attr // beware, may return null if an shadow that was to be marked as DEAD, was deleted in the meantime public PrismObject findOrAddShadowFromChange(ProvisioningContext ctx, Change change, OperationResult parentResult) throws SchemaException, CommunicationException, - ConfigurationException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException { + ConfigurationException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, EncryptionException { // Try to locate existing shadow in the repository List> accountList = searchShadowByIdenifiers(ctx, change, parentResult); @@ -490,7 +484,7 @@ public PrismObject findOrAddShadowFromChange(ProvisioningContext ctx public PrismObject findOrAddShadowFromChangeGlobalContext(ProvisioningContext globalCtx, Change change, OperationResult parentResult) throws SchemaException, CommunicationException, - ConfigurationException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException { + ConfigurationException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, EncryptionException { // Try to locate existing shadow in the repository List> accountList = searchShadowByIdenifiers(globalCtx, change, parentResult); @@ -563,7 +557,7 @@ public PrismObject findOrAddShadowFromChangeGlobalContext(Provisioni private PrismObject createNewShadowFromChange(ProvisioningContext ctx, Change change, OperationResult parentResult) throws SchemaException, CommunicationException, ConfigurationException, - SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException { + SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, EncryptionException { PrismObject shadow = change.getCurrentShadow(); @@ -754,7 +748,7 @@ private void processQueryMatchingRuleFilter(ObjectFilter filter, RefinedObje // Used when new resource object is discovered public PrismObject addDiscoveredRepositoryShadow(ProvisioningContext ctx, - PrismObject resourceShadow, OperationResult parentResult) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ObjectAlreadyExistsException, ExpressionEvaluationException { + PrismObject resourceShadow, OperationResult parentResult) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ObjectAlreadyExistsException, ExpressionEvaluationException, EncryptionException { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Adding new shadow from resource object: {}", resourceShadow.debugDump()); } @@ -769,7 +763,7 @@ public PrismObject addDiscoveredRepositoryShadow(ProvisioningContext return repoShadow; } - public String addNewProposedShadow(ProvisioningContext ctx, PrismObject shadow, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, ObjectAlreadyExistsException, SecurityViolationException { + public String addNewProposedShadow(ProvisioningContext ctx, PrismObject shadow, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, ObjectAlreadyExistsException, SecurityViolationException, EncryptionException { ResourceConsistencyType consistency = ctx.getResource().getConsistency(); if (consistency == null) { return null; @@ -808,14 +802,14 @@ public void handlePropesedShadowError(ProvisioningContext ctx, PrismObject shadowToAdd, ProvisioningOperationState>> opState, OperationResult parentResult) - throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ObjectAlreadyExistsException, ExpressionEvaluationException { + throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ObjectAlreadyExistsException, ExpressionEvaluationException, EncryptionException { if (opState.getExistingShadowOid() != null) { // We know that we have proposed shadow updateProposedShadowAfterAdd(ctx, shadowToAdd, opState, parentResult); @@ -1257,7 +1251,7 @@ private void addPropertyDelta(Collection repoDeltas, ItemPath containerPath, * Create a copy of a shadow that is suitable for repository storage. */ private PrismObject createRepositoryShadow(ProvisioningContext ctx, PrismObject shadow) - throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ExpressionEvaluationException { + throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ExpressionEvaluationException, EncryptionException { ResourceAttributeContainer attributesContainer = ShadowUtil.getAttributesContainer(shadow); @@ -1313,12 +1307,12 @@ private PrismObject createRepositoryShadow(ProvisioningContext ctx, setKindIfNecessary(repoShadowType, ctx.getObjectClassDefinition()); // setIntentIfNecessary(repoShadowType, objectClassDefinition); - // Store only password meta-data in repo + // Store only password meta-data in repo - unless there is explicit caching CredentialsType creds = repoShadowType.getCredentials(); if (creds != null) { PasswordType passwordType = creds.getPassword(); if (passwordType != null) { - ProvisioningUtil.cleanupShadowPassword(passwordType); + preparePasswordForStorage(passwordType, ctx.getObjectClassDefinition()); PrismObject owner = null; if (ctx.getTask() != null) { owner = ctx.getTask().getOwner(); @@ -1358,13 +1352,42 @@ private PrismObject createRepositoryShadow(ProvisioningContext ctx, return repoShadow; } + private void preparePasswordForStorage(PasswordType passwordType, + RefinedObjectClassDefinition objectClassDefinition) throws SchemaException, EncryptionException { + ProtectedStringType passwordValue = passwordType.getValue(); + if (passwordValue == null) { + return; + } + CachingStategyType cachingStategy = getPasswordCachingStrategy(objectClassDefinition); + if (cachingStategy != null && cachingStategy != CachingStategyType.NONE) { + if (!passwordValue.isHashed()) { + protector.hash(passwordValue); + } + return; + } else { + ProvisioningUtil.cleanupShadowPassword(passwordType); + } + } + + private CachingStategyType getPasswordCachingStrategy(RefinedObjectClassDefinition objectClassDefinition) { + ResourcePasswordDefinitionType passwordDefinition = objectClassDefinition.getPasswordDefinition(); + if (passwordDefinition == null) { + return null; + } + CachingPolicyType passwordCachingPolicy = passwordDefinition.getCaching(); + if (passwordCachingPolicy == null) { + return null; + } + return passwordCachingPolicy.getCachingStategy(); + } + public void modifyShadow( ProvisioningContext ctx, PrismObject oldRepoShadow, Collection modifications, ProvisioningOperationState>>> opState, OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, ConfigurationException, CommunicationException, ExpressionEvaluationException { + throws SchemaException, ObjectNotFoundException, ConfigurationException, CommunicationException, ExpressionEvaluationException, EncryptionException { PendingOperationType existingPendingOperation = null; if (ResourceTypeUtil.getRecordPendingOperations(ctx.getResource()) == RecordPendingOperationsType.ALL) { @@ -1400,11 +1423,11 @@ public void modifyShadow( /** * Really modifies shadow attributes. It applies the changes. It is used for synchronous operations and also for - * applying the results of completed asynchronous operations. + * applying the results of completed asynchronous operations. */ public void modifyShadowAttributes(ProvisioningContext ctx, PrismObject shadow, Collection modifications, OperationResult parentResult) - throws SchemaException, ObjectNotFoundException, ConfigurationException, CommunicationException, ExpressionEvaluationException { + throws SchemaException, ObjectNotFoundException, ConfigurationException, CommunicationException, ExpressionEvaluationException, EncryptionException { Collection shadowChanges = extractRepoShadowChanges(ctx, shadow, modifications); if (shadowChanges != null && !shadowChanges.isEmpty()) { LOGGER.trace( @@ -1453,7 +1476,7 @@ private boolean isResourceModification(ItemDelta itemDelta) { @SuppressWarnings("rawtypes") private Collection extractRepoShadowChanges(ProvisioningContext ctx, PrismObject shadow, Collection objectChange) - throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ExpressionEvaluationException { + throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ExpressionEvaluationException, EncryptionException { RefinedObjectClassDefinition objectClassDefinition = ctx.getObjectClassDefinition(); CachingStategyType cachingStrategy = ProvisioningUtil.getCachingStrategy(ctx); @@ -1488,14 +1511,51 @@ private Collection extractRepoShadowChanges(ProvisioningCon ProvisioningUtil.cleanupShadowActivation(valueToReplace.asContainerable()); } } else if (SchemaConstants.PATH_PASSWORD.equivalent(itemDelta.getParentPath())) { + addPasswordDelta(repoChanges, itemDelta, objectClassDefinition); continue; } normalizeDelta(itemDelta, objectClassDefinition); repoChanges.add(itemDelta); } + + return repoChanges; } + private void addPasswordDelta(Collection repoChanges, ItemDelta requestedPasswordDelta, RefinedObjectClassDefinition objectClassDefinition) throws SchemaException, EncryptionException { + if (!(requestedPasswordDelta.getPath().equivalent(SchemaConstants.PATH_PASSWORD_VALUE))) { + return; + } + CachingStategyType cachingStategy = getPasswordCachingStrategy(objectClassDefinition); + if (cachingStategy == null || cachingStategy == CachingStategyType.NONE) { + return; + } + PropertyDelta passwordValueDelta = (PropertyDelta)requestedPasswordDelta; + hashValues(passwordValueDelta.getValuesToAdd()); + hashValues(passwordValueDelta.getValuesToReplace()); + repoChanges.add(requestedPasswordDelta); + if (!(requestedPasswordDelta.getPath().equivalent(SchemaConstants.PATH_PASSWORD_VALUE))) { + return; + } + } + + + private void hashValues(Collection> pvals) throws SchemaException, EncryptionException { + if (pvals == null) { + return; + } + for (PrismPropertyValue pval: pvals) { + ProtectedStringType psVal = pval.getValue(); + if (psVal == null) { + return; + } + if (psVal.isHashed()) { + return; + } + protector.hash(psVal); + } + } + @SuppressWarnings("unchecked") public Collection updateShadow(ProvisioningContext ctx, PrismObject resourceShadow, Collection aprioriDeltas, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ExpressionEvaluationException { @@ -1586,7 +1646,6 @@ public PrismObject updateShadow(ProvisioningContext ctx, PrismObject normalizedRealValue = matchingRule.normalize(pval.getValue()); } attrAddDelta.addValueToAdd(new PrismPropertyValue(normalizedRealValue)); - LOGGER.trace("CURRENT ATTR:\n{}\nATTR DELTA:\n{}", currentResourceAttrProperty.debugDump(1), attrAddDelta.debugDump(1)); } shadowDelta.addModification(attrAddDelta); } else { @@ -1599,7 +1658,6 @@ public PrismObject updateShadow(ProvisioningContext ctx, PrismObject currentResourceNormalizedRealValue = matchingRule.normalize(currentResourceRealValue); } if (!currentResourceNormalizedRealValue.equals(oldRepoAttributeProperty.getRealValue())) { - LOGGER.trace("CURRENT ATTR:\n{}\ncurrentResourceNormalizedRealValue: {}", currentResourceAttrProperty.debugDump(1), currentResourceNormalizedRealValue); shadowDelta.addModificationReplaceProperty(currentResourceAttrProperty.getPath(), currentResourceNormalizedRealValue); } } else { @@ -1611,10 +1669,10 @@ public PrismObject updateShadow(ProvisioningContext ctx, PrismObject } } PropertyDelta attrDiff = oldRepoAttributeProperty.diff(normalizedCurrentResourceAttrProperty); - LOGGER.trace("DIFF:\n{}\n-\n{}\n=:\n{}", - oldRepoAttributeProperty==null?null:oldRepoAttributeProperty.debugDump(1), - normalizedCurrentResourceAttrProperty==null?null:normalizedCurrentResourceAttrProperty.debugDump(1), - attrDiff==null?null:attrDiff.debugDump(1)); +// LOGGER.trace("DIFF:\n{}\n-\n{}\n=:\n{}", +// oldRepoAttributeProperty==null?null:oldRepoAttributeProperty.debugDump(1), +// normalizedCurrentResourceAttrProperty==null?null:normalizedCurrentResourceAttrProperty.debugDump(1), +// attrDiff==null?null:attrDiff.debugDump(1)); if (attrDiff != null && !attrDiff.isEmpty()) { attrDiff.setParentPath(new ItemPath(ShadowType.F_ATTRIBUTES)); shadowDelta.addModification(attrDiff); @@ -1675,7 +1733,7 @@ public PrismObject updateShadow(ProvisioningContext ctx, PrismObject } else { throw new ConfigurationException("Unknown caching strategy "+cachingStrategy); } - + if (!shadowDelta.isEmpty()) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Updating repo shadow {} with delta:\n{}", oldRepoShadow, shadowDelta.debugDump(1)); @@ -1697,6 +1755,7 @@ public PrismObject updateShadow(ProvisioningContext ctx, PrismObject return oldRepoShadow; } } + private void compareUpdateProperty(ObjectDelta shadowDelta, ItemPath itemPath, PrismObject currentResourceShadow, PrismObject oldRepoShadow) { diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractBasicDummyTest.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractBasicDummyTest.java index 23c20be4876..7a039dc3835 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractBasicDummyTest.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractBasicDummyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Evolveum + * Copyright (c) 2010-2018 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,6 @@ package com.evolveum.midpoint.provisioning.impl.dummy; import static com.evolveum.midpoint.test.IntegrationTestTools.assertProvisioningAccountShadow; -import static com.evolveum.midpoint.test.IntegrationTestTools.display; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertNotNull; @@ -111,6 +110,8 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.CapabilitiesType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CapabilityCollectionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; @@ -121,6 +122,7 @@ import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ReadCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ScriptCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.TestConnectionCapabilityType; +import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; /** * The test of Provisioning service on the API level. The test is using dummy @@ -160,7 +162,7 @@ public static void assertCleanShutdown() throws Exception { @Test public void test000Integrity() throws Exception { final String TEST_NAME = "test000Integrity"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); display("Dummy resource instance", dummyResource.toString()); @@ -194,7 +196,7 @@ public void test000Integrity() throws Exception { @Test public void test010ListConnectors() throws Exception { final String TEST_NAME = "test010ListConnectors"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN OperationResult result = new OperationResult(AbstractBasicDummyTest.class.getName() + "." + TEST_NAME); @@ -245,7 +247,7 @@ public void test010ListConnectors() throws Exception { @Test public void test012ConnectorRediscovery() { final String TEST_NAME = "test012ConnectorRediscovery"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN OperationResult result = new OperationResult(AbstractBasicDummyTest.class.getName() + "." + TEST_NAME); @@ -253,9 +255,7 @@ public void test012ConnectorRediscovery() { Set discoverLocalConnectors = connectorManager.discoverLocalConnectors(result); // THEN - result.computeStatus(); - display("discoverLocalConnectors result", result); - TestUtil.assertSuccess("discoverLocalConnectors failed", result); + assertSuccess("discoverLocalConnectors failed", result); assertTrue("Rediscovered something", discoverLocalConnectors.isEmpty()); } @@ -266,7 +266,7 @@ public void test012ConnectorRediscovery() { @Test public void test015ListResourcesNoFetch() throws Exception { final String TEST_NAME = "test015ListResourcesNoFetch"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN Task task = taskManager.createTaskInstance(AbstractBasicDummyTest.class.getName() + "." + TEST_NAME); OperationResult result = task.getResult(); @@ -276,9 +276,7 @@ public void test015ListResourcesNoFetch() throws Exception { SearchResultList> resources = provisioningService.searchObjects(ResourceType.class, null, options, task, result); // THEN - result.computeStatus(); - display("searchObjects result", result); - TestUtil.assertSuccess(result); + assertSuccess(result); assertFalse("No resources found", resources.isEmpty()); for (PrismObject resource : resources) { @@ -311,7 +309,7 @@ public void test015ListResourcesNoFetch() throws Exception { @Test public void test020Connection() throws Exception { final String TEST_NAME = "test020Connection"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN Task task = createTask(TEST_NAME); OperationResult result = task.getResult(); @@ -387,7 +385,7 @@ public void test020Connection() throws Exception { @Test public void test021Configuration() throws Exception { final String TEST_NAME = "test021Configuration"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN OperationResult result = new OperationResult(AbstractBasicDummyTest.class.getName() + "." + TEST_NAME); @@ -442,7 +440,7 @@ protected void assertConfigurationProperty(PrismProperty confProp) { @Test public void test022ParsedSchema() throws Exception { final String TEST_NAME = "test022ParsedSchema"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN // THEN @@ -470,7 +468,7 @@ public void test022ParsedSchema() throws Exception { @Test public void test023RefinedSchema() throws Exception { final String TEST_NAME = "test023RefinedSchema"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN // WHEN @@ -556,7 +554,7 @@ public void test023RefinedSchema() throws Exception { @Test public void test024ParsedSchemaAgain() throws Exception { final String TEST_NAME = "test024ParsedSchemaAgain"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN // THEN @@ -576,7 +574,7 @@ public void test024ParsedSchemaAgain() throws Exception { @Test public void test028Capabilities() throws Exception { final String TEST_NAME = "test028Capabilities"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN OperationResult result = new OperationResult(AbstractBasicDummyTest.class.getName() @@ -658,7 +656,7 @@ protected void assertNativeCredentialsCapability(CredentialsCapabilityType capCr @Test public void test029CapabilitiesRepo() throws Exception { final String TEST_NAME = "test029CapabilitiesRepo"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN OperationResult result = new OperationResult(AbstractBasicDummyTest.class.getName() @@ -856,7 +854,7 @@ public void test031ResourceAndConnectorCachingForceFresh() throws Exception { @Test public void test040ApplyDefinitionShadow() throws Exception { final String TEST_NAME = "test040ApplyDefinitionShadow"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN Task task = createTask(TEST_NAME); @@ -882,7 +880,7 @@ public void test040ApplyDefinitionShadow() throws Exception { @Test public void test041ApplyDefinitionAddShadowDelta() throws Exception { final String TEST_NAME = "test041ApplyDefinitionAddShadowDelta"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN Task task = createTask(TEST_NAME); @@ -909,7 +907,7 @@ public void test041ApplyDefinitionAddShadowDelta() throws Exception { @Test public void test042ApplyDefinitionResource() throws Exception { final String TEST_NAME = "test042ApplyDefinitionResource"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN Task task = createTask(TEST_NAME); @@ -939,7 +937,7 @@ public void test042ApplyDefinitionResource() throws Exception { @Test public void test043ApplyDefinitionAddResourceDelta() throws Exception { final String TEST_NAME = "test043ApplyDefinitionAddResourceDelta"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN Task task = createTask(TEST_NAME); @@ -996,7 +994,7 @@ public void test050SelfTest() throws Exception { @Test public void test080TestAttributesToReturn() throws Exception { final String TEST_NAME = "test080TestAttributesToReturn"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN Task task = taskManager.createTaskInstance(); @@ -1024,7 +1022,7 @@ public void test080TestAttributesToReturn() throws Exception { @Test public void test090ConnectorStatsAfterSomeUse() throws Exception { final String TEST_NAME = "test090ConnectorStatsAfterSomeUse"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN Task task = createTask(TEST_NAME); OperationResult result = task.getResult(); @@ -1137,7 +1135,7 @@ public void test100AddAccountWill() throws Exception { assertEquals("Username is wrong", transformNameFromResource(ACCOUNT_WILL_USERNAME), dummyAccount.getName()); assertEquals("Fullname is wrong", "Will Turner", dummyAccount.getAttributeValue("fullname")); assertTrue("The account is not enabled", dummyAccount.isEnabled()); - assertEquals("Wrong password", "3lizab3th", dummyAccount.getPassword()); + assertEquals("Wrong password", ACCOUNT_WILL_PASSWORD, dummyAccount.getPassword()); // Check if the shadow is still in the repo (e.g. that the consistency or sync haven't removed it) PrismObject shadowFromRepo = repositoryService.getObject(ShadowType.class, @@ -1151,7 +1149,7 @@ public void test100AddAccountWill() throws Exception { // MID-3860 assertShadowPasswordMetadata(shadowFromRepo, true, start, end, null, null); - assertNoShadowPassword(shadowFromRepo); + assertRepoShadowCredentials(shadowFromRepo, ACCOUNT_WILL_PASSWORD); lastPasswordModifyStart = start; lastPasswordModifyEnd = end; @@ -1193,7 +1191,7 @@ protected void checkRepoAccountShadowWill(PrismObject accountRepo, X @Test public void test102GetAccount() throws Exception { final String TEST_NAME = "test102GetAccount"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN OperationResult result = new OperationResult(AbstractBasicDummyTest.class.getName() + "." + TEST_NAME); @@ -1234,7 +1232,7 @@ public void test102GetAccount() throws Exception { @Test public void test103GetAccountNoFetch() throws Exception { final String TEST_NAME="test103GetAccountNoFetch"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN OperationResult result = new OperationResult(AbstractBasicDummyTest.class.getName() + "."+TEST_NAME); @@ -1252,9 +1250,8 @@ public void test103GetAccountNoFetch() throws Exception { // THEN XMLGregorianCalendar endTs = clock.currentTimeXMLGregorianCalendar(); - result.computeStatus(); display("getObject result", result); - TestUtil.assertSuccess(result); + assertSuccess(result); assertCounterIncrement(InternalCounters.SHADOW_FETCH_OPERATION_COUNT, 0); display("Retrieved account shadow", shadow); @@ -1273,7 +1270,7 @@ public void test103GetAccountNoFetch() throws Exception { @Test public void test105ApplyDefinitionModifyDelta() throws Exception { final String TEST_NAME = "test105ApplyDefinitionModifyDelta"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN Task task = createTask(TEST_NAME); @@ -1288,12 +1285,9 @@ public void test105ApplyDefinitionModifyDelta() throws Exception { provisioningService.applyDefinition(accountDelta, task, result); // THEN - result.computeStatus(); - display("applyDefinition result", result); - TestUtil.assertSuccess(result); + assertSuccess(result); accountDelta.checkConsistence(true, true, true); - TestUtil.assertSuccess("applyDefinition(modify delta) result", result); assertSteadyResource(); } @@ -1306,7 +1300,7 @@ public void test105ApplyDefinitionModifyDelta() throws Exception { @Test public void test106GetModifiedAccount() throws Exception { final String TEST_NAME = "test106GetModifiedAccount"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // GIVEN OperationResult result = new OperationResult(AbstractBasicDummyTest.class.getName() + "." + TEST_NAME); rememberCounter(InternalCounters.SHADOW_FETCH_OPERATION_COUNT); @@ -1319,14 +1313,12 @@ public void test106GetModifiedAccount() throws Exception { XMLGregorianCalendar startTs = clock.currentTimeXMLGregorianCalendar(); // WHEN - TestUtil.displayWhen(TEST_NAME); + displayWhen(TEST_NAME); PrismObject shadow = provisioningService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, null, result); // THEN - TestUtil.displayThen(TEST_NAME); - result.computeStatus(); - display("getObject result", result); - TestUtil.assertSuccess(result); + displayThen(TEST_NAME); + assertSuccess(result); assertCounterIncrement(InternalCounters.SHADOW_FETCH_OPERATION_COUNT, 1); XMLGregorianCalendar endTs = clock.currentTimeXMLGregorianCalendar(); @@ -1350,6 +1342,7 @@ public void test106GetModifiedAccount() throws Exception { assertRepoShadowCachedAttributeValue(shadowRepo, DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_WEAPON_NAME, "sword", "love"); assertRepoShadowCachedAttributeValue(shadowRepo, DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_LOOT_NAME, 42); assertRepoShadowCacheActivation(shadowRepo, ActivationStatusType.DISABLED); + assertRepoShadowCredentials(shadowRepo, ACCOUNT_WILL_PASSWORD); checkConsistency(shadow); @@ -1361,7 +1354,7 @@ public void test106GetModifiedAccount() throws Exception { @Test public void test999Shutdown() throws Exception { final String TEST_NAME = "test999Shutdown"; - TestUtil.displayTestTitle(TEST_NAME); + displayTestTitle(TEST_NAME); // WHEN provisioningService.shutdown(); @@ -1446,5 +1439,27 @@ protected void assertRepoShadowCacheActivation(PrismObject shadowRep ActivationStatusType administrativeStatus = activationType.getAdministrativeStatus(); assertNull("Unexpected activation administrativeStatus in repo shadow "+shadowRepo+": "+administrativeStatus, administrativeStatus); } + + protected void assertRepoShadowCredentials(PrismObject shadowRepo, String expectedPassword) throws SchemaException, EncryptionException { + CredentialsType credentials = shadowRepo.asObjectable().getCredentials(); + if (expectedPassword == null && credentials == null) { + return; + } + assertNotNull("Missing credentendials in repo shadow "+shadowRepo, credentials); + PasswordType passwordType = credentials.getPassword(); + if (expectedPassword == null && passwordType == null) { + return; + } + assertNotNull("Missing password credential in repo shadow "+shadowRepo, passwordType); + // TODO: assert password meta-data + assertRepoShadowPasswordValue(shadowRepo, passwordType, expectedPassword); + } + + protected void assertRepoShadowPasswordValue(PrismObject shadowRepo, PasswordType passwordType, + String expectedPassword) throws SchemaException, EncryptionException { + ProtectedStringType passwordValue = passwordType.getValue(); + assertNull("Unexpected password value in repo shadow "+shadowRepo, passwordValue); + } + } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractDummyTest.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractDummyTest.java index 2fc1b20e4fb..e7b8e2a5631 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractDummyTest.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractDummyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Evolveum + * Copyright (c) 2010-2018 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ */ package com.evolveum.midpoint.provisioning.impl.dummy; -import static com.evolveum.midpoint.test.IntegrationTestTools.display; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertNull; @@ -104,6 +103,8 @@ public abstract class AbstractDummyTest extends AbstractProvisioningIntegrationT protected static final File ACCOUNT_WILL_FILE = new File(TEST_DIR, "account-will.xml"); protected static final String ACCOUNT_WILL_OID = "c0c010c0-d34d-b44f-f11d-33322212dddd"; protected static final String ACCOUNT_WILL_USERNAME = "Will"; + protected static final String ACCOUNT_WILL_PASSWORD = "3lizab3th"; + protected static final String ACCOUNT_WILL_PASSWORD_NEW = "3lizab3th123"; protected static final XMLGregorianCalendar ACCOUNT_WILL_ENABLE_TIMESTAMP = XmlTypeConverter.createXMLGregorianCalendar(2013, 5, 30, 12, 30, 42); protected static final File ACCOUNT_ELIZABETH_FILE = new File(TEST_DIR, "account-elizabeth.xml"); @@ -119,6 +120,7 @@ public abstract class AbstractDummyTest extends AbstractProvisioningIntegrationT protected static final File ACCOUNT_MORGAN_FILE = new File(TEST_DIR, "account-morgan.xml"); protected static final String ACCOUNT_MORGAN_OID = "c0c010c0-d34d-b44f-f11d-444400008888"; protected static final String ACCOUNT_MORGAN_NAME = "morgan"; + protected static final String ACCOUNT_MORGAN_PASSWORD = "sh1verM3T1mb3rs"; protected static final File ACCOUNT_LECHUCK_FILE = new File(TEST_DIR, "account-lechuck.xml"); protected static final String ACCOUNT_LECHUCK_OID = "c0c010c0-d34d-b44f-f11d-444400009aa9"; @@ -159,6 +161,8 @@ public abstract class AbstractDummyTest extends AbstractProvisioningIntegrationT protected ResourceType resourceType; protected static DummyResource dummyResource; protected static DummyResourceContoller dummyResourceCtl; + + protected String accountWillCurrentPassword = ACCOUNT_WILL_PASSWORD; // Testing connector discovery @Autowired(required = true) diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java index cc07c092c89..b32ec3d3e60 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummy.java @@ -68,6 +68,7 @@ import com.evolveum.midpoint.prism.util.PrismAsserts; import com.evolveum.midpoint.prism.util.PrismTestUtil; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.provisioning.api.ItemComparisonResult; import com.evolveum.midpoint.provisioning.api.ResourceObjectShadowChangeDescription; import com.evolveum.midpoint.provisioning.impl.ProvisioningTestUtil; import com.evolveum.midpoint.provisioning.impl.opendj.TestOpenDj; @@ -170,6 +171,14 @@ protected String getDrakeRepoIcfName() { return DRAKE_USERNAME; } + protected ItemComparisonResult getExpectedPasswordComparisonResultMatch() { + return ItemComparisonResult.NOT_APPLICABLE; + } + + protected ItemComparisonResult getExpectedPasswordComparisonResultMismatch() { + return ItemComparisonResult.NOT_APPLICABLE; + } + @Override public void initSystem(Task initTask, OperationResult initResult) throws Exception { super.initSystem(initTask, initResult); @@ -225,7 +234,7 @@ public void test101AddAccountWithoutName() throws Exception { assertNotNull("No dummy account", dummyAccount); assertEquals("Fullname is wrong", "Captain Morgan", dummyAccount.getAttributeValue("fullname")); assertTrue("The account is not enabled", dummyAccount.isEnabled()); - assertEquals("Wrong password", "sh1verM3T1mb3rs", dummyAccount.getPassword()); + assertEquals("Wrong password", ACCOUNT_MORGAN_PASSWORD, dummyAccount.getPassword()); // Check if the shadow is in the repo PrismObject shadowFromRepo = repositoryService.getObject(ShadowType.class, @@ -234,12 +243,14 @@ public void test101AddAccountWithoutName() throws Exception { display("Repository shadow", shadowFromRepo.debugDump()); checkRepoAccountShadow(shadowFromRepo); + // MID-4397 + assertRepoShadowCredentials(shadowFromRepo, ACCOUNT_MORGAN_PASSWORD); checkConsistency(account.asPrismObject()); assertSteadyResource(); } - + // test102-test106 in the superclasses /** @@ -428,9 +439,7 @@ public void test109ModifiedAccountCleanup() throws Exception { PrismObject shadow = provisioningService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, null, result); // THEN - result.computeStatus(); - display("getObject result", result); - TestUtil.assertSuccess(result); + assertSuccess(result); assertCounterIncrement(InternalCounters.SHADOW_FETCH_OPERATION_COUNT, 1); XMLGregorianCalendar endTs = clock.currentTimeXMLGregorianCalendar(); @@ -518,9 +527,7 @@ public boolean handle(PrismObject object, OperationResult parentResu // THEN XMLGregorianCalendar endTs = clock.currentTimeXMLGregorianCalendar(); - result.computeStatus(); - display("searchObjectsIterative result", result); - TestUtil.assertSuccess(result); + assertSuccess(result); assertCounterIncrement(InternalCounters.SHADOW_FETCH_OPERATION_COUNT, 1); assertEquals(4, foundObjects.size()); @@ -586,10 +593,7 @@ public void test111SeachIterativeNoFetch() throws Exception { final XMLGregorianCalendar startTs = clock.currentTimeXMLGregorianCalendar(); final List> foundObjects = new ArrayList>(); - ResultHandler handler = new ResultHandler() { - - @Override - public boolean handle(PrismObject shadow, OperationResult parentResult) { + ResultHandler handler = (shadow, parentResult) -> { foundObjects.add(shadow); assertTrue(shadow.canRepresent(ShadowType.class)); @@ -606,8 +610,8 @@ public boolean handle(PrismObject shadow, OperationResult parentResu } return true; - } - }; + }; + Collection> options = SelectorOptions.createCollection(GetOperationOptions.createNoFetch()); @@ -617,9 +621,7 @@ public boolean handle(PrismObject shadow, OperationResult parentResu provisioningService.searchObjectsIterative(ShadowType.class, query, options, handler, null, result); // THEN - result.computeStatus(); - display("searchObjectsIterative result", result); - TestUtil.assertSuccess(result); + assertSuccess(result); assertCounterIncrement(InternalCounters.SHADOW_FETCH_OPERATION_COUNT, 0); display("Found shadows", foundObjects); @@ -644,19 +646,16 @@ public void test112SeachIterativeKindIntent() throws Exception { display("query", query); final List> foundObjects = new ArrayList>(); - ResultHandler handler = new ResultHandler() { - - @Override - public boolean handle(PrismObject object, OperationResult parentResult) { - foundObjects.add(object); - return true; - } - }; rememberCounter(InternalCounters.SHADOW_FETCH_OPERATION_COUNT); // WHEN - provisioningService.searchObjectsIterative(ShadowType.class, query, null, handler, null, result); + provisioningService.searchObjectsIterative(ShadowType.class, query, null, + (object, parentResult) -> { + foundObjects.add(object); + return true; + }, + null, result); // THEN result.computeStatus(); @@ -690,7 +689,7 @@ private int countProtected(List> shadows) @Test public void test113SearchAllShadowsInRepository() throws Exception { - TestUtil.displayTestTitle("test113SearchAllShadowsInRepository"); + displayTestTitle("test113SearchAllShadowsInRepository"); // GIVEN OperationResult result = new OperationResult(TestDummy.class.getName() + ".test113SearchAllShadowsInRepository"); @@ -702,9 +701,7 @@ public void test113SearchAllShadowsInRepository() throws Exception { query, null, result); // THEN - result.computeStatus(); - display("searchObjects result", result); - TestUtil.assertSuccess(result); + assertSuccess(result); display("Found " + allShadows.size() + " shadows"); display("Found shadows", allShadows); @@ -748,7 +745,7 @@ public void test114SearchAllAccounts() throws Exception { @Test public void test115CountAllAccounts() throws Exception { - TestUtil.displayTestTitle("test115CountAllAccounts"); + displayTestTitle("test115CountAllAccounts"); // GIVEN OperationResult result = new OperationResult(TestDummy.class.getName() + ".test115countAllShadows"); @@ -798,7 +795,7 @@ public void test116SearchNullQueryResource() throws Exception { @Test public void test117CountNullQueryResource() throws Exception { - TestUtil.displayTestTitle("test117CountNullQueryResource"); + displayTestTitle("test117CountNullQueryResource"); // GIVEN OperationResult result = new OperationResult(TestDummy.class.getName() + ".test117CountNullQueryResource"); @@ -916,17 +913,13 @@ public void test119SearchAllAccountsMaxStaleness() throws Exception { assertSteadyResource(); } - - @Test - public void test123ModifyObjectReplace() throws Exception { - final String TEST_NAME = "test123ModifyObjectReplace"; + public void test120ModifyObjectReplace() throws Exception { + final String TEST_NAME = "test120ModifyObjectReplace"; displayTestTitle(TEST_NAME); - Task task = taskManager.createTaskInstance(TestDummy.class.getName() - + "." + TEST_NAME); + Task task = createTask(TEST_NAME); OperationResult result = task.getResult(); - syncServiceMock.reset(); ObjectDelta delta = ObjectDelta.createModificationReplaceProperty(ShadowType.class, @@ -935,13 +928,13 @@ public void test123ModifyObjectReplace() throws Exception { delta.checkConsistence(); // WHEN + displayWhen(TEST_NAME); provisioningService.modifyObject(ShadowType.class, delta.getOid(), delta.getModifications(), new OperationProvisioningScriptsType(), null, task, result); // THEN - result.computeStatus(); - display("modifyObject result", result); - TestUtil.assertSuccess(result); + displayThen(TEST_NAME); + assertSuccess(result); delta.checkConsistence(); assertDummyAccountAttributeValues(transformNameFromResource(ACCOUNT_WILL_USERNAME), willIcfUid, @@ -953,13 +946,12 @@ public void test123ModifyObjectReplace() throws Exception { } @Test - public void test124ModifyObjectAddPirate() throws Exception { - TestUtil.displayTestTitle("test124ModifyObjectAddPirate"); + public void test121ModifyObjectAddPirate() throws Exception { + final String TEST_NAME = "test121ModifyObjectAddPirate"; + displayTestTitle(TEST_NAME); - Task syncTask = taskManager.createTaskInstance(TestDummy.class.getName() - + ".test124ModifyObjectAddPirate"); - OperationResult result = new OperationResult(TestOpenDj.class.getName() - + ".test124ModifyObjectAddPirate"); + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); syncServiceMock.reset(); ObjectDelta delta = ObjectDelta.createModificationAddProperty(ShadowType.class, @@ -970,13 +962,13 @@ public void test124ModifyObjectAddPirate() throws Exception { delta.checkConsistence(); // WHEN + displayWhen(TEST_NAME); provisioningService.modifyObject(ShadowType.class, delta.getOid(), delta.getModifications(), - new OperationProvisioningScriptsType(), null, syncTask, result); + new OperationProvisioningScriptsType(), null, task, result); // THEN - result.computeStatus(); - display("modifyObject result", result); - TestUtil.assertSuccess(result); + displayThen(TEST_NAME); + assertSuccess(result); delta.checkConsistence(); // check if attribute was changed @@ -989,13 +981,12 @@ public void test124ModifyObjectAddPirate() throws Exception { } @Test - public void test125ModifyObjectAddCaptain() throws Exception { - TestUtil.displayTestTitle("test125ModifyObjectAddCaptain"); + public void test122ModifyObjectAddCaptain() throws Exception { + final String TEST_NAME = "test122ModifyObjectAddCaptain"; + displayTestTitle(TEST_NAME); - Task syncTask = taskManager.createTaskInstance(TestDummy.class.getName() - + ".test125ModifyObjectAddCaptain"); - OperationResult result = new OperationResult(TestOpenDj.class.getName() - + ".test125ModifyObjectAddCaptain"); + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); syncServiceMock.reset(); ObjectDelta delta = ObjectDelta.createModificationAddProperty(ShadowType.class, @@ -1006,13 +997,13 @@ public void test125ModifyObjectAddCaptain() throws Exception { delta.checkConsistence(); // WHEN + displayWhen(TEST_NAME); provisioningService.modifyObject(ShadowType.class, delta.getOid(), delta.getModifications(), - new OperationProvisioningScriptsType(), null, syncTask, result); + new OperationProvisioningScriptsType(), null, task, result); // THEN - result.computeStatus(); - display("modifyObject result", result); - TestUtil.assertSuccess(result); + displayThen(TEST_NAME); + assertSuccess(result); delta.checkConsistence(); // check if attribute was changed @@ -1025,13 +1016,12 @@ public void test125ModifyObjectAddCaptain() throws Exception { } @Test - public void test126ModifyObjectDeletePirate() throws Exception { - TestUtil.displayTestTitle("test126ModifyObjectDeletePirate"); + public void test123ModifyObjectDeletePirate() throws Exception { + final String TEST_NAME = "test123ModifyObjectDeletePirate"; + displayTestTitle(TEST_NAME); - Task syncTask = taskManager.createTaskInstance(TestDummy.class.getName() - + ".test126ModifyObjectDeletePirate"); - OperationResult result = new OperationResult(TestOpenDj.class.getName() - + ".test126ModifyObjectDeletePirate"); + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); syncServiceMock.reset(); ObjectDelta delta = ObjectDelta.createModificationDeleteProperty(ShadowType.class, @@ -1040,13 +1030,13 @@ public void test126ModifyObjectDeletePirate() throws Exception { delta.checkConsistence(); // WHEN + displayWhen(TEST_NAME); provisioningService.modifyObject(ShadowType.class, delta.getOid(), delta.getModifications(), - new OperationProvisioningScriptsType(), null, syncTask, result); + new OperationProvisioningScriptsType(), null, task, result); // THEN - result.computeStatus(); - display("modifyObject result", result); - TestUtil.assertSuccess(result); + displayThen(TEST_NAME); + assertSuccess(result); delta.checkConsistence(); // check if attribute was changed @@ -1063,12 +1053,11 @@ public void test126ModifyObjectDeletePirate() throws Exception { * unless the mechanism to compensate for this works properly. */ @Test - public void test127ModifyObjectAddCaptainAgain() throws Exception { - final String TEST_NAME = "test127ModifyObjectAddCaptainAgain"; + public void test124ModifyAccountWillAddCaptainAgain() throws Exception { + final String TEST_NAME = "test124ModifyAccountWillAddCaptainAgain"; displayTestTitle(TEST_NAME); - Task task = taskManager.createTaskInstance(TestDummy.class.getName() - + "." + TEST_NAME); + Task task = createTask(TEST_NAME); OperationResult result = task.getResult(); syncServiceMock.reset(); @@ -1078,13 +1067,13 @@ public void test127ModifyObjectAddCaptainAgain() throws Exception { delta.checkConsistence(); // WHEN + displayWhen(TEST_NAME); provisioningService.modifyObject(ShadowType.class, delta.getOid(), delta.getModifications(), new OperationProvisioningScriptsType(), null, task, result); // THEN - result.computeStatus(); - display("modifyObject result", result); - TestUtil.assertSuccess(result); + displayThen(TEST_NAME); + assertSuccess(result); delta.checkConsistence(); // check if attribute was changed @@ -1096,16 +1085,108 @@ public void test127ModifyObjectAddCaptainAgain() throws Exception { assertSteadyResource(); } + /** + * MID-4397 + */ + @Test + public void test125CompareAccountWillPassword() throws Exception { + final String TEST_NAME = "test125CompareAccountWillPassword"; + displayTestTitle(TEST_NAME); + + testComparePassword(TEST_NAME, "match", ACCOUNT_WILL_OID, accountWillCurrentPassword, getExpectedPasswordComparisonResultMatch()); + testComparePassword(TEST_NAME, "mismatch", ACCOUNT_WILL_OID, "I woulD NeVeR ever USE this PASSword", getExpectedPasswordComparisonResultMismatch()); + + assertSteadyResource(); + } + + /** + * MID-4397 + */ + @Test + public void test126ModifyAccountWillPassword() throws Exception { + final String TEST_NAME = "test126ModifyAccountWillPassword"; + displayTestTitle(TEST_NAME); + + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + syncServiceMock.reset(); + + ObjectDelta delta = createAccountPaswordDelta(ACCOUNT_WILL_OID, ACCOUNT_WILL_PASSWORD_NEW); + display("ObjectDelta", delta); + + // WHEN + displayWhen(TEST_NAME); + provisioningService.modifyObject(ShadowType.class, delta.getOid(), delta.getModifications(), + new OperationProvisioningScriptsType(), null, task, result); + + // THEN + displayThen(TEST_NAME); + assertSuccess(result); + + // Check if the account was created in the dummy resource + DummyAccount dummyAccount = getDummyAccountAssert(transformNameFromResource(ACCOUNT_WILL_USERNAME), willIcfUid); + assertNotNull("No dummy account", dummyAccount); + assertEquals("Wrong password", ACCOUNT_WILL_PASSWORD_NEW, dummyAccount.getPassword()); + accountWillCurrentPassword = ACCOUNT_WILL_PASSWORD_NEW; + + // Check if the shadow is in the repo + PrismObject repoShadow = repositoryService.getObject(ShadowType.class, + ACCOUNT_WILL_OID, null, result); + assertNotNull("Shadow was not created in the repository", repoShadow); + display("Repository shadow", repoShadow); + + checkRepoAccountShadow(repoShadow); + assertRepoShadowCredentials(repoShadow, ACCOUNT_WILL_PASSWORD_NEW); + + syncServiceMock.assertNotifySuccessOnly(); + + assertSteadyResource(); + } + + /** + * MID-4397 + */ + @Test + public void test127CompareAccountWillPassword() throws Exception { + final String TEST_NAME = "test125CompareAccountWillPassword"; + displayTestTitle(TEST_NAME); + + testComparePassword(TEST_NAME, "match", ACCOUNT_WILL_OID, accountWillCurrentPassword, getExpectedPasswordComparisonResultMatch()); + testComparePassword(TEST_NAME, "mismatch old password", ACCOUNT_WILL_OID, ACCOUNT_WILL_PASSWORD, getExpectedPasswordComparisonResultMismatch()); + testComparePassword(TEST_NAME, "mismatch", ACCOUNT_WILL_OID, "I woulD NeVeR ever USE this PASSword", getExpectedPasswordComparisonResultMismatch()); + + assertSteadyResource(); + } + + protected void testComparePassword(final String TEST_NAME, String tag, String shadowOid, String expectedPassword, ItemComparisonResult expectedResult) throws Exception { + Task task = createTask(TEST_NAME+".tag"); + OperationResult result = task.getResult(); + syncServiceMock.reset(); + + // WHEN (match) + displayWhen(TEST_NAME); + ItemComparisonResult comparisonResult = provisioningService.compare(ShadowType.class, shadowOid, SchemaConstants.PATH_PASSWORD_VALUE, + expectedPassword, task, result); + + // THEN (match) + displayThen(TEST_NAME); + assertSuccess(result); + + display("Comparison result ("+tag+")", comparisonResult); + assertEquals("Wrong comparison result ("+tag+")", expectedResult, comparisonResult); + + syncServiceMock.assertNoNotifcations(); + } + /** * Set a null value to the (native) dummy attribute. The UCF layer should filter that out. */ @Test - public void test128NullAttributeValue() throws Exception { - final String TEST_NAME = "test128NullAttributeValue"; + public void test129NullAttributeValue() throws Exception { + final String TEST_NAME = "test129NullAttributeValue"; displayTestTitle(TEST_NAME); - Task task = taskManager.createTaskInstance(TestDummy.class.getName() - + "." + TEST_NAME); + Task task = createTask(TEST_NAME); OperationResult result = task.getResult(); syncServiceMock.reset(); @@ -1113,12 +1194,12 @@ public void test128NullAttributeValue() throws Exception { willDummyAccount.replaceAttributeValue(DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME, null); // WHEN + displayWhen(TEST_NAME); PrismObject accountWill = provisioningService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, task, result); // THEN - result.computeStatus(); - display("getObject result", result); - TestUtil.assertSuccess(result); + displayThen(TEST_NAME); + assertSuccess(result); ResourceAttributeContainer attributesContainer = ShadowUtil.getAttributesContainer(accountWill); ResourceAttribute titleAttribute = attributesContainer.findAttribute(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME)); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyCaching.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyCaching.java index 2a30844c42d..9c93d244238 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyCaching.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyCaching.java @@ -34,7 +34,9 @@ import com.evolveum.icf.dummy.resource.DummyAccount; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.crypto.EncryptionException; import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.provisioning.api.ItemComparisonResult; import com.evolveum.midpoint.provisioning.impl.ProvisioningTestUtil; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.SelectorOptions; @@ -51,10 +53,13 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CachingMetadataType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsStorageTypeType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; +import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; /** * Almost the same as TestDummy but this is using a caching configuration. @@ -78,6 +83,16 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti protected File getResourceDummyFilename() { return RESOURCE_DUMMY_FILE; } + + @Override + protected ItemComparisonResult getExpectedPasswordComparisonResultMatch() { + return ItemComparisonResult.MATCH; + } + + @Override + protected ItemComparisonResult getExpectedPasswordComparisonResultMismatch() { + return ItemComparisonResult.MISMATCH; + } /** * Make a native modification to an account and read it from the cache. Make sure that @@ -296,6 +311,14 @@ protected void assertRepoShadowCacheActivation(PrismObject shadowRep assertEquals("Wrong activation administrativeStatus in repo shadow "+shadowRepo, expectedAdministrativeStatus, administrativeStatus); } + @Override + protected void assertRepoShadowPasswordValue(PrismObject shadowRepo, PasswordType passwordType, + String expectedPassword) throws SchemaException, EncryptionException { + ProtectedStringType protectedStringType = passwordType.getValue(); + assertNotNull("No password value in repo shadow "+shadowRepo, protectedStringType); + assertProtectedString("Wrong password value in repo shadow "+shadowRepo, expectedPassword, protectedStringType, CredentialsStorageTypeType.HASHING); + } + /** * We do not know what the timestamp should be. But some timestamp should be there. */ diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyExtra.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyExtra.java index 97eec3dbb28..f4d5e50a46d 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyExtra.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyExtra.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017 Evolveum + * Copyright (c) 2015-2018 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ */ package com.evolveum.midpoint.provisioning.impl.dummy; -import static com.evolveum.midpoint.test.IntegrationTestTools.display; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertTrue; @@ -40,7 +39,6 @@ import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.crypto.EncryptionException; import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; import com.evolveum.midpoint.schema.processor.ResourceSchema; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; @@ -282,7 +280,7 @@ public void test499DeleteAccountElizabeth() throws Exception { @Override protected void checkAccountWill(PrismObject shadow, OperationResult result, XMLGregorianCalendar startTs, XMLGregorianCalendar endTs) throws SchemaException, EncryptionException { super.checkAccountWill(shadow, result, startTs, endTs); - assertPassword(shadow.asObjectable(), "3lizab3th"); + assertPassword(shadow.asObjectable(), accountWillCurrentPassword); } } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java index 6df7ddd657e..e06cb46940a 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/opendj/TestOpenDj.java @@ -2757,7 +2757,7 @@ public void test701ConfiguredCapabilityNoRead() throws Exception{ null, task, result); AssertJUnit .fail("Expected unsupported operation exception, but haven't got one."); - } catch (SystemException ex) { + } catch (UnsupportedOperationException ex) { // this is expected.. } } @@ -2776,7 +2776,7 @@ public void test702ConfiguredCapabilityNoCreate() throws Exception{ provisioningService.addObject(shadow, null, null, task, result); AssertJUnit .fail("Expected unsupported operation exception, but haven't got one."); - } catch (SystemException ex) { + } catch (UnsupportedOperationException ex) { LOGGER.info("exception: {}", ex.getMessage(), ex); // this is expected.. } @@ -2795,7 +2795,7 @@ public void test703ConfiguredCapabilityNoDelete() throws Exception{ provisioningService.deleteObject(ShadowType.class, ACCOUNT_WILL_OID, null, null, task, result); AssertJUnit .fail("Expected unsupported operation exception, but haven't got one."); - } catch (SystemException ex) { + } catch (UnsupportedOperationException ex) { // this is expected.. } } @@ -2815,7 +2815,7 @@ public void test704ConfiguredCapabilityNoUpdate() throws Exception{ provisioningService.modifyObject(ShadowType.class, ACCOUNT_WILL_OID, modifications, null, null, task, result); AssertJUnit .fail("Expected unsupported operation exception, but haven't got one."); - } catch (SystemException ex) { + } catch (UnsupportedOperationException ex) { // this is expected.. } } diff --git a/provisioning/provisioning-impl/src/test/resources/dummy/dummy-caching/resource-dummy.xml b/provisioning/provisioning-impl/src/test/resources/dummy/dummy-caching/resource-dummy.xml index 21da4387ab2..fed9bf551a5 100644 --- a/provisioning/provisioning-impl/src/test/resources/dummy/dummy-caching/resource-dummy.xml +++ b/provisioning/provisioning-impl/src/test/resources/dummy/dummy-caching/resource-dummy.xml @@ -1,6 +1,6 @@