Skip to content

Commit

Permalink
Fixing prism findItemDelta() which also fixes password policy issues …
Browse files Browse the repository at this point in the history
…(MID-2857) +tests and cleanup
  • Loading branch information
semancik committed May 16, 2016
1 parent cc5f015 commit bb5db18
Show file tree
Hide file tree
Showing 8 changed files with 323 additions and 49 deletions.
Expand Up @@ -21,7 +21,9 @@
import javax.xml.namespace.QName;

import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.path.IdItemPathSegment;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.path.ItemPathSegment;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.exception.SchemaException;

Expand Down Expand Up @@ -140,26 +142,34 @@ public ItemDelta<?,?> getSubDelta(ItemPath path) {
if (path.isEmpty()) {
return this;
}
Long id = null;
ItemPathSegment first = path.first();
if (first instanceof IdItemPathSegment) {
id = ((IdItemPathSegment)first).getId();
path = path.rest();
}
ItemDefinition itemDefinition = getDefinition().findItemDefinition(path);
ItemDelta<?,?> itemDelta = itemDefinition.createEmptyDelta(getPath().subPath(path));
itemDelta.addValuesToAdd(findItemValues(path, getValuesToAdd()));
itemDelta.addValuesToDelete(findItemValues(path, getValuesToDelete()));
itemDelta.setValuesToReplace(findItemValues(path, getValuesToReplace()));
itemDelta.addValuesToAdd(findItemValues(id, path, getValuesToAdd()));
itemDelta.addValuesToDelete(findItemValues(id, path, getValuesToDelete()));
itemDelta.setValuesToReplace(findItemValues(id, path, getValuesToReplace()));
if (itemDelta.isEmpty()) {
return null;
}
return itemDelta;
}

private Collection findItemValues(ItemPath path, Collection<PrismContainerValue<V>> cvalues) {
private Collection findItemValues(Long id, ItemPath path, Collection<PrismContainerValue<V>> cvalues) {
if (cvalues == null) {
return null;
}
Collection<PrismValue> subValues = new ArrayList<PrismValue>();
for (PrismContainerValue<V> cvalue: cvalues) {
Item<?,?> item = cvalue.findItem(path);
if (item != null) {
subValues.addAll(item.getValues());
if (id == null || id == cvalue.getId()) {
Item<?,?> item = cvalue.findItem(path);
if (item != null) {
subValues.addAll(PrismValue.cloneCollection(item.getValues()));
}
}
}
return subValues;
Expand Down
Expand Up @@ -28,6 +28,7 @@
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.parser.XPathHolder;
import com.evolveum.midpoint.prism.path.IdItemPathSegment;
import com.evolveum.midpoint.prism.path.IdentifierPathSegment;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.path.ItemPath.CompareResult;
import com.evolveum.midpoint.prism.path.ItemPathSegment;
Expand Down Expand Up @@ -302,6 +303,9 @@ public void clearValuesToReplace() {
}

public void addValuesToAdd(Collection<V> newValues) {
if (newValues == null) {
return;
}
for (V val : newValues) {
addValueToAdd(val);
}
Expand Down Expand Up @@ -358,12 +362,18 @@ private boolean removeValue(V valueToRemove, Collection<V> set) {
}

public void mergeValuesToAdd(Collection<V> newValues) {
if (newValues == null) {
return;
}
for (V val : newValues) {
mergeValueToAdd(val);
}
}

public void mergeValuesToAdd(V[] newValues) {
if (newValues == null) {
return;
}
for (V val : newValues) {
mergeValueToAdd(val);
}
Expand All @@ -383,6 +393,9 @@ public void mergeValueToAdd(V newValue) {
}

public void addValuesToDelete(Collection<V> newValues) {
if (newValues == null) {
return;
}
for (V val : newValues) {
addValueToDelete(val);
}
Expand Down Expand Up @@ -457,6 +470,9 @@ public void resetValuesToDelete() {
}

public void setValuesToReplace(Collection<V> newValues) {
if (newValues == null) {
return;
}
if (valuesToAdd != null) {
throw new IllegalStateException("Delta " + this
+ " already has values to add ("+valuesToAdd+"), attempt to set value to replace ("+newValues+")");
Expand Down Expand Up @@ -754,6 +770,9 @@ public static <DD extends ItemDelta> DD findItemDelta(Collection<? extends ItemD
if (deltaType.isAssignableFrom(delta.getClass()) && delta.getPath().equivalent(propertyPath)) {
return (DD) delta;
}
if ((delta instanceof ContainerDelta<?>) && delta.getPath().isSubPath(propertyPath)) {
return (DD) ((ContainerDelta)delta).getSubDelta(propertyPath.substract(delta.getPath()));
}
}
return null;
}
Expand Down
Expand Up @@ -1032,4 +1032,10 @@ public static void assertRefEquivalent(String message, PrismReferenceValue expec
assertEquals(message+": wrong target oid", expected.getOid(), actual.getOid());
assertEquals(message+": wrong target type", expected.getTargetType(), actual.getTargetType());
}

public static void assertInstanceOf(Class<?> expectedClass, Object object) {
assertNotNull("Expected that object will be instance of "+expectedClass+", but it is null", object);
assertTrue("Expected that "+object+" will be instance of "+expectedClass+", but it is "+object.getClass(),
expectedClass.isAssignableFrom(object.getClass()));
}
}
Expand Up @@ -23,6 +23,8 @@
import java.io.IOException;
import java.util.Collection;

import javax.xml.datatype.XMLGregorianCalendar;

import com.evolveum.midpoint.prism.delta.*;

import org.testng.AssertJUnit;
Expand All @@ -39,6 +41,7 @@
import com.evolveum.midpoint.prism.polystring.PolyString;
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.util.DOMUtil;
import com.evolveum.midpoint.util.DebugUtil;
import com.evolveum.midpoint.util.PrettyPrinter;
Expand Down Expand Up @@ -1079,7 +1082,65 @@ public void testObjectDeltaApplyToReplaceEmpty() throws Exception {
PrismAsserts.assertNoItem(user, UserType.F_ADDITIONAL_NAMES);
user.checkConsistence();
}

@Test
public void testObjectDeltaFindItemDeltaModifyProperty() throws Exception {
System.out.println("\n\n===[ testObjectDeltaFindItemDeltaModifyProperty ]===\n");
// GIVEN

ObjectDelta<UserType> userDelta = createDeltaForFindItem();
ItemPath itemDeltaPath = new ItemPath(UserType.F_GIVEN_NAME);

// WHEN
ItemDelta<PrismValue, ItemDefinition> itemDelta = userDelta.findItemDelta(itemDeltaPath);

// THEN
PrismAsserts.assertInstanceOf(PropertyDelta.class, itemDelta);
assertEquals(itemDeltaPath, itemDelta.getPath());
PrismAsserts.assertPropertyValues("Wrong replace values in "+itemDelta,
((PropertyDelta)itemDelta).getValuesToReplace(), "Guybrush");
}

@Test
public void testObjectDeltaFindItemDeltaModifyPropertyInContainer() throws Exception {
System.out.println("\n\n===[ testObjectDeltaFindItemDeltaModifyPropertyInContainer ]===\n");
// GIVEN
ObjectDelta<UserType> userDelta = createDeltaForFindItem();
System.out.println("Object delta:\n"+userDelta.debugDump());

ItemPath itemDeltaPath = new ItemPath(UserType.F_ACTIVATION, ActivationType.F_ENABLED);

// WHEN
ItemDelta<PrismValue, ItemDefinition> itemDelta = userDelta.findItemDelta(itemDeltaPath);

// THEN
System.out.println("Item delta:\n"+(itemDelta==null?"null":itemDelta.debugDump()));
PrismAsserts.assertInstanceOf(PropertyDelta.class, itemDelta);
assertEquals(itemDeltaPath, itemDelta.getPath());
PrismAsserts.assertPropertyValues("Wrong add values in "+itemDelta,
((PropertyDelta)itemDelta).getValuesToAdd(), Boolean.TRUE);
}

private ObjectDelta<UserType> createDeltaForFindItem() throws SchemaException {
ObjectDelta<UserType> userDelta = ObjectDelta.createModificationAddProperty(UserType.class, USER_FOO_OID,
UserType.F_LOCALITY, PrismTestUtil.getPrismContext(), "Caribbean");
userDelta.addModificationReplaceProperty(UserType.F_GIVEN_NAME, "Guybrush");

ContainerDelta<ActivationType> activationDelta = userDelta.createContainerModification(new ItemPath(UserType.F_ACTIVATION));
PrismContainerValue<ActivationType> activationCVal = new PrismContainerValue();
activationDelta.addValueToAdd(activationCVal);

PrismProperty<Boolean> enabledProperty = activationCVal.createProperty(ActivationType.F_ENABLED);
enabledProperty.setRealValue(Boolean.TRUE);

PrismProperty<XMLGregorianCalendar> validFromProperty = activationCVal.createProperty(ActivationType.F_VALID_FROM);
validFromProperty.setRealValue(XmlTypeConverter.createXMLGregorianCalendar(20016, 5, 16, 19, 8, 33));

userDelta.addModification(activationDelta);

return userDelta;
}

/**
* MODIFY/add + MODIFY/add
*/
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2015 Evolveum
* Copyright (c) 2010-2016 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -70,23 +70,7 @@ public class PasswordPolicyProcessor {
@Autowired(required = true)
ModelObjectResolver resolver;

void processPasswordPolicy(ValuePolicyType passwordPolicy, PrismProperty password, OperationResult result)
throws PolicyViolationException, SchemaException {

if (passwordPolicy == null) {
LOGGER.trace("Skipping processing password policies. Password policy not specified.");
return;
}

String passwordValue = determinePasswordValue(password);

boolean isValid = PasswordPolicyUtils.validatePassword(passwordValue, passwordPolicy, result);

if (!isValid) {
result.computeStatus();
throw new PolicyViolationException("Provided password does not satisfy password policies. " + result.getMessage());
}
}


<F extends FocusType> void processPasswordPolicy(LensFocusContext<F> focusContext,
LensContext<F> context, Task task, OperationResult result)
Expand All @@ -110,21 +94,21 @@ <F extends FocusType> void processPasswordPolicy(LensFocusContext<F> focusContex
return;
}

PrismProperty<PasswordType> password = null;
PrismProperty<ProtectedStringType> passwordValueProperty = null;
PrismObject<F> user;
if (ChangeType.ADD == userDelta.getChangeType()) {
user = focusContext.getDelta().getObjectToAdd();
if (user != null) {
password = user.findProperty(SchemaConstants.PATH_PASSWORD_VALUE);
passwordValueProperty = user.findProperty(SchemaConstants.PATH_PASSWORD_VALUE);
}
if (password == null){
if (passwordValueProperty == null){
if (wasExecuted(userDelta, focusContext)){
LOGGER.trace("Skipping processing password policies. User addition was already executed.");
return;
}
}
} else if (ChangeType.MODIFY == userDelta.getChangeType()) {
PropertyDelta<PasswordType> passwordValueDelta;
PropertyDelta<ProtectedStringType> passwordValueDelta;
if (userDelta != null) {
passwordValueDelta = userDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE);
if (passwordValueDelta == null) {
Expand All @@ -133,14 +117,14 @@ <F extends FocusType> void processPasswordPolicy(LensFocusContext<F> focusContex
}
if (userDelta.getChangeType() == ChangeType.MODIFY && passwordValueDelta != null) {
if (passwordValueDelta.isAdd()) {
password = (PrismProperty<PasswordType>) passwordValueDelta.getItemNewMatchingPath(null);
passwordValueProperty = (PrismProperty<ProtectedStringType>) passwordValueDelta.getItemNewMatchingPath(null);
} else if (passwordValueDelta.isDelete()) {
password = null;
passwordValueProperty = null;
} else {
password = (PrismProperty<PasswordType>) passwordValueDelta.getItemNewMatchingPath(null);
passwordValueProperty = (PrismProperty<ProtectedStringType>) passwordValueDelta.getItemNewMatchingPath(null);
}
} else {
password = (PrismProperty<PasswordType>) passwordValueDelta.getItemNewMatchingPath(null);
passwordValueProperty = (PrismProperty<ProtectedStringType>) passwordValueDelta.getItemNewMatchingPath(null);
}
}
}
Expand All @@ -153,8 +137,26 @@ <F extends FocusType> void processPasswordPolicy(LensFocusContext<F> focusContex
passwordPolicy = focusContext.getOrgPasswordPolicy();
}

processPasswordPolicy(passwordPolicy, password, result);
processPasswordPolicy(passwordPolicy, passwordValueProperty, result);

}

private void processPasswordPolicy(ValuePolicyType passwordPolicy, PrismProperty<ProtectedStringType> passwordProperty, OperationResult result)
throws PolicyViolationException, SchemaException {

if (passwordPolicy == null) {
LOGGER.trace("Skipping processing password policies. Password policy not specified.");
return;
}

String passwordValue = determinePasswordValue(passwordProperty);

boolean isValid = PasswordPolicyUtils.validatePassword(passwordValue, passwordPolicy, result);

if (!isValid) {
result.computeStatus();
throw new PolicyViolationException("Provided password does not satisfy password policies. " + result.getMessage());
}
}

private <F extends FocusType> boolean wasExecuted(ObjectDelta<UserType> userDelta, LensFocusContext<F> focusContext){
Expand Down Expand Up @@ -365,12 +367,12 @@ private <F extends ObjectType> boolean isCheckOrgPolicy(LensContext<F> context)


// On missing password this returns empty string (""). It is then up to password policy whether it allows empty passwords or not.
private String determinePasswordValue(PrismProperty<PasswordType> password) {
private String determinePasswordValue(PrismProperty<ProtectedStringType> password) {
if (password == null || password.getValue(ProtectedStringType.class) == null) {
return null;
}

ProtectedStringType passValue = password.getValue(ProtectedStringType.class).getValue();
ProtectedStringType passValue = password.getRealValue();

if (passValue == null) {
return null;
Expand Down
Expand Up @@ -308,7 +308,7 @@ public class AbstractConfiguredModelIntegrationTest extends AbstractModelIntegra

public static final String DUMMY_ORG_TOP_NAME = DummyResourceContoller.ORG_TOP_NAME;

protected static final String PASSWORD_POLICY_GLOBAL_FILENAME = COMMON_DIR + "/password-policy-global.xml";
protected static final File PASSWORD_POLICY_GLOBAL_FILE = new File(COMMON_DIR, "password-policy-global.xml");
protected static final String PASSWORD_POLICY_GLOBAL_OID = "12344321-0000-0000-0000-000000000003";

protected static final File ORG_MONKEY_ISLAND_FILE = new File(COMMON_DIR, "org-monkey-island.xml");
Expand Down

0 comments on commit bb5db18

Please sign in to comment.