Skip to content

Commit

Permalink
fix for MID-5534 native vs. configured capabilities - activation, tests
Browse files Browse the repository at this point in the history
  • Loading branch information
katkav committed Jul 19, 2019
1 parent eb24fd9 commit 38bcc04
Show file tree
Hide file tree
Showing 8 changed files with 343 additions and 40 deletions.
Expand Up @@ -333,4 +333,15 @@ public static <T extends CapabilityType> boolean hasNativeCapability(Capabiliti
}
return getCapability(nativeCaps.getAny(), capabilityClass) != null;
}

public static <T extends CapabilityType> boolean hasConfiguredCapability(CapabilitiesType capabilities, Class<T> capabilityClass) {
if (capabilities == null) {
return false;
}
CapabilityCollectionType configuredCaps = capabilities.getConfigured();
if (configuredCaps == null) {
return false;
}
return getCapability(configuredCaps.getAny(), capabilityClass) != null;
}
}
Expand Up @@ -335,6 +335,14 @@ public <T extends CapabilityType> boolean hasNativeCapability(Class<T> capabili
return CapabilityUtil.hasNativeCapability(connectorCapabilities, capabilityClass);
}

public <T extends CapabilityType> boolean hasConfiguredCapability(Class<T> capabilityClass) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException {
CapabilitiesType connectorCapabilities = getConnectorCapabilities(capabilityClass);
if (connectorCapabilities == null) {
return false;
}
return CapabilityUtil.hasConfiguredCapability(connectorCapabilities, capabilityClass);
}

private <T extends CapabilityType> CapabilitiesType getConnectorCapabilities(Class<T> operationCapabilityClass) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException {
return resourceManager.getConnectorCapabilities(getResource(), getObjectClassDefinition(), operationCapabilityClass);
}
Expand Down
Expand Up @@ -1343,7 +1343,9 @@ public <T extends CapabilityType> CapabilitiesType getConnectorCapabilities(Reso
}


return applyObjectClassCapabilities(connectorCapabilities, objectClassDefinition);
CapabilitiesType finalCapabilities = applyObjectClassCapabilities(connectorCapabilities, objectClassDefinition);
LOGGER.trace("Returning final capabilities:\n{} ", finalCapabilities);
return finalCapabilities;

}

Expand All @@ -1355,21 +1357,23 @@ private CapabilitiesType applyObjectClassCapabilities(CapabilitiesType connector

CapabilitiesType objectClassCapabilities = objectClassDefinition.getCapabilities();
if (objectClassCapabilities == null) {
if (connectorCapabilities == null) {
return null;
}
LOGGER.trace("No capabilities for {} specified, skipping merge.", objectClassDefinition);
return connectorCapabilities;
}

CapabilitiesType finalCapabilities = new CapabilitiesType();
finalCapabilities.setNative(connectorCapabilities.getNative());
CapabilityCollectionType configured = objectClassCapabilities.getConfigured();
if (configured == null) {
LOGGER.trace("Empty capabilities in {} specified, skipping merge", objectClassDefinition);
return connectorCapabilities;
}

if (objectClassCapabilities == null) {
finalCapabilities.setConfigured(connectorCapabilities.getConfigured());
return finalCapabilities;
CapabilitiesType finalCapabilities = new CapabilitiesType();
if (connectorCapabilities.getNative() != null) {
finalCapabilities.setNative(connectorCapabilities.getNative());
}

CapabilityCollectionType configured = objectClassCapabilities.getConfigured();
if (!hasConfiguredCapabilities(connectorCapabilities)) {
LOGGER.trace("No configured capabilities found for connector, replacing with capabilities defined for {}", objectClassDefinition);
finalCapabilities.setConfigured(configured);
return finalCapabilities;
}
Expand Down
Expand Up @@ -1175,8 +1175,6 @@ private PrismObject<ShadowType> executeEntitlementChangesModify(ProvisioningCont
entitlementConverter.collectEntitlementsAsObjectOperation(ctx, roMap, associationDelta, subjectShadowBefore, subjectShadowAfter, parentResult);
}

// shadowAfter.findOrCreateContainer(ShadowType.F_ASSOCIATION).addAll((Collection) association.getClonedValues());
// entitlementConverter.processEntitlementsAdd(resource, shadowAfter, objectClassDefinition);
}
}

Expand Down Expand Up @@ -1422,9 +1420,8 @@ private Collection<Operation> determineActivationChange(ProvisioningContext ctx,
ResourceType resource = ctx.getResource();
Collection<Operation> operations = new ArrayList<>();

// CapabilitiesType connectorCapabilities = ctx.getConnectorCapabilities(UpdateCapabilityType.class);
ActivationCapabilityType activationCapability = ctx.getEffectiveCapability(ActivationCapabilityType.class);

LOGGER.trace("Found activation capability: {}", PrettyPrinter.prettyPrint(activationCapability));
// administrativeStatus
PropertyDelta<ActivationStatusType> enabledPropertyDelta = PropertyDeltaCollectionsUtil.findPropertyDelta(objectChange,
SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS);
Expand All @@ -1436,19 +1433,17 @@ private Collection<Operation> determineActivationChange(ProvisioningContext ctx,
}
ActivationStatusType status = enabledPropertyDelta.getPropertyNewMatchingPath().getRealValue();
LOGGER.trace("Found activation administrativeStatus change to: {}", status);

if (ctx.hasNativeCapability(ActivationCapabilityType.class)) {
// Native activation, need to check if there is not also change to simulated activation which may be in conflict
checkSimulatedActivationAdministrativeStatus(ctx, objectChange, status, activationCapability, shadow, result);
operations.add(new PropertyModificationOperation(enabledPropertyDelta));
} else {
// Try to simulate activation capability

if (ctx.hasConfiguredCapability(ActivationCapabilityType.class)) {
PropertyModificationOperation activationAttribute = convertToSimulatedActivationAdministrativeStatusAttribute(
ctx, enabledPropertyDelta, shadow, status, activationCapability, result);
if (activationAttribute != null) {
operations.add(activationAttribute);
}
}
} else {
LOGGER.trace("Native activation capability, creating property modification");
operations.add(new PropertyModificationOperation(enabledPropertyDelta));
}
}

// validFrom
Expand Down Expand Up @@ -1489,17 +1484,14 @@ private Collection<Operation> determineActivationChange(ProvisioningContext ctx,
}
LockoutStatusType status = lockoutPropertyDelta.getPropertyNewMatchingPath().getRealValue();
LOGGER.trace("Found activation lockoutStatus change to: {}", status);

if (ctx.hasNativeCapability(ActivationCapabilityType.class)) {
// Native lockout, need to check if there is not also change to simulated activation which may be in conflict
checkSimulatedActivationLockoutStatus(ctx, objectChange, status, activationCapability, shadow, result);
operations.add(new PropertyModificationOperation(lockoutPropertyDelta));
} else {
if (ctx.hasConfiguredCapability(ActivationCapabilityType.class)) {
// Try to simulate lockout capability
PropertyModificationOperation activationAttribute = convertToSimulatedActivationLockoutStatusAttribute(
ctx, lockoutPropertyDelta, shadow, status, activationCapability, result);
operations.add(activationAttribute);
}
} else {
operations.add(new PropertyModificationOperation(lockoutPropertyDelta));
}
}

return operations;
Expand Down Expand Up @@ -1605,13 +1597,15 @@ private void transformActivationAttributesAdd(ProvisioningContext ctx, ShadowTyp
ActivationCapabilityType activationCapability = ctx.getEffectiveCapability(ActivationCapabilityType.class);

if (activation.getAdministrativeStatus() != null) {
if (!ctx.hasNativeCapability(ActivationCapabilityType.class)) {
if (ctx.hasConfiguredCapability(ActivationCapabilityType.class)) {
LOGGER.trace("Start converting simulated activation attribute.");
ActivationStatusCapabilityType capActStatus = getActivationAdministrativeStatusFromSimulatedActivation(
ctx, activationCapability, shadow, result);
if (capActStatus == null) {
throw new SchemaException("Attempt to change activation/administrativeStatus on "+ctx.getResource()+" that has neither native" +
" nor simulated activation capability");
}
LOGGER.trace("Activation status capability: \n{}", capActStatus);
ResourceAttribute<?> newSimulatedAttr = getSimulatedActivationAdministrativeStatusAttribute(ctx, shadow,
capActStatus, result);
if (newSimulatedAttr != null) {
Expand All @@ -1624,6 +1618,7 @@ private void transformActivationAttributesAdd(ProvisioningContext ctx, ShadowTyp
newSimulatedAttrRealValue = getDisableValue(capActStatus, simulatedAttrValueClass);
}

LOGGER.trace("Converted activation status value to {}, attribute {}", newSimulatedAttrRealValue, newSimulatedAttr);
Item existingSimulatedAttr = attributesContainer.findItem(newSimulatedAttr.getElementName());
if (!isBlank(newSimulatedAttrRealValue)) {
PrismPropertyValue newSimulatedAttrValue = prismContext.itemFactory().createPropertyValue(newSimulatedAttrRealValue);
Expand All @@ -1638,12 +1633,14 @@ private void transformActivationAttributesAdd(ProvisioningContext ctx, ShadowTyp
}
activation.setAdministrativeStatus(null);
}
}else {
LOGGER.trace("No activation simulated capability, nothing to do.");
}
}

// TODO enable non-string lockout values (MID-3374)
if (activation.getLockoutStatus() != null) {
if (!ctx.hasNativeCapability(ActivationCapabilityType.class)) {
if (ctx.hasConfiguredCapability(ActivationCapabilityType.class)) {
ActivationLockoutStatusCapabilityType capActStatus = getActivationLockoutStatusFromSimulatedActivation(
ctx, activationCapability, shadow, result);
if (capActStatus == null) {
Expand Down Expand Up @@ -2003,13 +2000,11 @@ private void completeActivation(ProvisioningContext ctx, PrismObject<ShadowType>

if (resourceObjectType.getActivation() != null || CapabilityUtil.isCapabilityEnabled(activationCapability)) {
ActivationType activationType = null;

if (ctx.hasNativeCapability(ActivationCapabilityType.class)) {
activationType = resourceObjectType.getActivation();

} else if (CapabilityUtil.isCapabilityEnabled(activationCapability)) {

if (ctx.hasConfiguredCapability(ActivationCapabilityType.class) && CapabilityUtil.isCapabilityEnabled(activationCapability)){
activationType = convertFromSimulatedActivationAttributes(resourceType, resourceObject, activationCapability, parentResult);

} else if (ctx.hasNativeCapability(ActivationCapabilityType.class)) {
activationType = resourceObjectType.getActivation();
} else {
// No activation capability, nothing to do
}
Expand Down Expand Up @@ -2306,6 +2301,8 @@ private PropertyModificationOperation convertToSimulatedActivationAdministrative
return null;
}

LOGGER.trace("Simulted activation attribute: {}", simulatedAttribute);

Class<?> simulatedAttrValueClass = getAttributeValueClass(ctx, shadow, simulatedAttribute, capActStatus);

PropertyDelta<?> simulatedAttrDelta;
Expand All @@ -2315,9 +2312,11 @@ private PropertyModificationOperation convertToSimulatedActivationAdministrative
ItemPath.create(ShadowType.F_ATTRIBUTES, simulatedAttribute.getElementName()), simulatedAttribute.getDefinition(), simulatedAttribute.getRealValue());
} else if (status == ActivationStatusType.ENABLED) {
Object enableValue = getEnableValue(capActStatus, simulatedAttrValueClass);
LOGGER.trace("Value for simulated enable {}", enableValue);
simulatedAttrDelta = createActivationPropDelta(simulatedAttribute.getElementName(), simulatedAttribute.getDefinition(), enableValue);
} else {
Object disableValue = getDisableValue(capActStatus, simulatedAttrValueClass);
LOGGER.trace("Value for simulated disable {}", disableValue);
simulatedAttrDelta = createActivationPropDelta(simulatedAttribute.getElementName(), simulatedAttribute.getDefinition(), disableValue);
}

Expand Down
Expand Up @@ -15,12 +15,23 @@
*/
package com.evolveum.midpoint.testing.story;

import com.evolveum.icf.dummy.resource.DummyAccount;
import com.evolveum.icf.dummy.resource.DummyResource;
import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchema;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.test.DummyResourceContoller;
import com.evolveum.midpoint.test.asserter.UserAsserter;
import com.evolveum.midpoint.test.util.MidPointTestConstants;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
import org.testng.AssertJUnit;
import org.testng.annotations.Test;

import java.io.File;
Expand All @@ -39,16 +50,41 @@ public class TestConfiguredCapabilitiesActivation extends AbstractStoryTest {
protected static final File RESOURCE_DUMMY_ACTIVATION_FILE = new File(TEST_DIR, "resource-dummy-activation.xml");
protected static final String RESOURCE_DUMMY_ACTIVATION_OID = "4bac305c-ed1f-4919-9670-e11863156811";
protected static final String RESOURCE_DUMMY_ACTIVATION_NAME = "activation";

private static final File RESOURCE_DUMMY_ACTIVATION_NATIVE_FILE = new File(TEST_DIR, "resource-dummy-activation-native.xml");
private static final String RESOURCE_DUMMY_ACTIVATION_NATIVE_OID = "4bac305c-ed1f-4919-aaaa-e11863156811";
private static final String RESOURCE_DUMMY_ACTIVATION_NATIVE_NAME = "activation-native";

protected static final File SHADOW_FILE = new File(TEST_DIR, "shadow-sample.xml");
protected static final String SHADOW_OID = "6925f5a7-2acb-409b-b2e1-94a6534a9745";

private static final File ROLE_PIRATE_FILE = new File(TEST_DIR, "role-pirate.xml");
private static final String ROLE_PIRATE_OID = "34713dae-8d56-4717-b184-86d02c9a2361";

private DummyResourceContoller dummyActivationNativeController;
private DummyResource dummyActivationNativeResource;
private ResourceType resourceActivationNativeType;
private PrismObject<ResourceType> resourceActivationNative;


@Override
public void initSystem(Task initTask, OperationResult initResult) throws Exception {
super.initSystem(initTask, initResult);

initDummyResourcePirate(RESOURCE_DUMMY_ACTIVATION_NAME, RESOURCE_DUMMY_ACTIVATION_FILE, RESOURCE_DUMMY_ACTIVATION_OID, initTask, initResult);
addObject(SHADOW_FILE);

// dummyActivationNativeController = DummyResourceContoller.create(RESOURCE_DUMMY_ACTIVATION_NATIVE_NAME, resourceActivationNative);
// dummyActivationNativeController.extendSchemaPirate();
// dummyActivationNativeResource = dummyActivationNativeController.getDummyResource();
// resourceActivationNative = importAndGetObjectFromFile(ResourceType.class, RESOURCE_DUMMY_ACTIVATION_NATIVE_FILE, RESOURCE_DUMMY_ACTIVATION_NATIVE_OID, initTask, initResult);
// resourceActivationNativeType = resourceActivationNative.asObjectable();
// dummyActivationNativeController.setResource(resourceActivationNative);

dummyActivationNativeController = initDummyResource(RESOURCE_DUMMY_ACTIVATION_NATIVE_NAME, RESOURCE_DUMMY_ACTIVATION_NATIVE_FILE, RESOURCE_DUMMY_ACTIVATION_NATIVE_OID, initTask, initResult);
dummyActivationNativeResource = dummyActivationNativeController.getDummyResource();

importObjectFromFile(ROLE_PIRATE_FILE, initResult);
}

@Test
Expand All @@ -75,5 +111,62 @@ public void test000ImportAccount() throws Exception {
assertTrue("Configured addRemoveAttributeValues is not disabled", Boolean.FALSE.equals(capUpdate.isAddRemoveAttributeValues()));
*/
}

@Test
public void test010assignJack() throws Exception {
String TEST_NAME = "test010assignJack";
displayTestTitle(TEST_NAME);

Task task = createTask(TEST_NAME);
OperationResult result = task.getResult();

//GIVEN
PrismObject<UserType> userJackBefore = getUser(USER_JACK_OID);
UserAsserter.forUser(userJackBefore).activation().assertAdministrativeStatus(ActivationStatusType.ENABLED);
UserAsserter.forUser(userJackBefore).links().assertLinks(0);

//WHEN
assumeAssignmentPolicy(AssignmentPolicyEnforcementType.FULL);
assignRole(USER_JACK_OID, ROLE_PIRATE_OID, task, result);
display("Result:\n", result);
assertSuccess(result);


//THEN
displayThen(TEST_NAME);
PrismObject<UserType> userJackAfter = getUser(USER_JACK_OID);
UserAsserter.forUser(userJackAfter).links().assertLinks(1);

DummyAccount jackAccount = dummyActivationNativeResource.getAccountByUsername(USER_JACK_USERNAME);
display("Jack Dummy Account: ", jackAccount.debugDump());
String enableDisableValue = jackAccount.getAttributeValue("privileges");
AssertJUnit.assertEquals("Unexpected activation status value: " + enableDisableValue, "false", enableDisableValue);
}

@Test
public void test011modifyActivationJack() throws Exception {
String TEST_NAME = "test011modifyActivationJack";
displayTestTitle(TEST_NAME);

Task task = createTask(TEST_NAME);
OperationResult result = task.getResult();

PrismObject<UserType> userJack = getUser(USER_JACK_OID);
UserAsserter.forUser(userJack).activation().assertAdministrativeStatus(ActivationStatusType.ENABLED);

//WHEN
modifyUserReplace(USER_JACK_OID, SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS, task, result, ActivationStatusType.DISABLED);

//THEN
displayThen(TEST_NAME);
PrismObject<UserType> userJackAfter = getUser(USER_JACK_OID);
UserAsserter.forUser(userJackAfter).activation().assertAdministrativeStatus(ActivationStatusType.DISABLED);

DummyAccount jackAccount = dummyActivationNativeResource.getAccountByUsername(USER_JACK_USERNAME);
display("Jack Dummy Account: ", jackAccount.debugDump());

String enableDisableValue = jackAccount.getAttributeValue("privileges");
AssertJUnit.assertEquals("Unexpected activation status value: " + enableDisableValue, "true", enableDisableValue);
}

}

0 comments on commit 38bcc04

Please sign in to comment.