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 3e440ad241a..f123c47ebe1 100644 --- 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 @@ -9413,7 +9413,17 @@ - Specification of the type (class) of the object to apply this template to. + Specification of the type (class) of the object to apply this definition to. + + + + + + + Specification of the subtype of the object to apply this template to. + If no subtype is specified then this definition will be applied to all subtypes. + The subtype is compared agains the subType property but it is also compared to the + deprecated employeeType, roleType, orgType and serviceType properties. diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java index 33cd92a82fa..0e56f0e5804 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java @@ -244,7 +244,7 @@ public PrismObjectDefinition getEditObjectDefinition(P ObjectTemplateType objectTemplateType; try { - objectTemplateType = schemaTransformer.determineObjectTemplate(object.getCompileTimeClass(), phase, result); + objectTemplateType = schemaTransformer.determineObjectTemplate(object, phase, result); } catch (ConfigurationException | ObjectNotFoundException e) { result.recordFatalError(e); throw e; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelUtils.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelUtils.java index 9ad79d1affb..a6c6b075239 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelUtils.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelUtils.java @@ -15,6 +15,9 @@ */ package com.evolveum.midpoint.model.impl.controller; +import java.util.ArrayList; +import java.util.List; + import javax.xml.namespace.QName; import com.evolveum.midpoint.model.api.ModelAuthorizationAction; @@ -31,6 +34,9 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ServiceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; @@ -97,8 +103,14 @@ public static String getOperationUrlFromDelta(ObjectDelta } throw new IllegalArgumentException("Unknown delta type "+delta); } + + public static ObjectPolicyConfigurationType determineObjectPolicyConfiguration(PrismObject object, SystemConfigurationType systemConfigurationType) throws ConfigurationException { + List subTypes = determineSubTypes(object); + return determineObjectPolicyConfiguration(object.getCompileTimeClass(), subTypes, systemConfigurationType); + } - public static ObjectPolicyConfigurationType determineObjectPolicyConfiguration(Class objectClass, SystemConfigurationType systemConfigurationType) throws ConfigurationException { + public static ObjectPolicyConfigurationType determineObjectPolicyConfiguration(Class objectClass, List objectSubtypes, SystemConfigurationType systemConfigurationType) throws ConfigurationException { + ObjectPolicyConfigurationType applicablePolicyConfigurationType = null; for (ObjectPolicyConfigurationType aPolicyConfigurationType: systemConfigurationType.getDefaultObjectPolicyConfiguration()) { QName typeQName = aPolicyConfigurationType.getType(); ObjectTypes objectType = ObjectTypes.getObjectTypeFromTypeQName(typeQName); @@ -106,9 +118,19 @@ public static ObjectPolicyConfigurationType determineObje throw new ConfigurationException("Unknown type "+typeQName+" in default object policy definition in system configuration"); } if (objectType.getClassDefinition() == objectClass) { - return aPolicyConfigurationType; + String aSubType = aPolicyConfigurationType.getSubType(); + if (aSubType == null) { + if (applicablePolicyConfigurationType == null) { + applicablePolicyConfigurationType = aPolicyConfigurationType; + } + } else if (objectSubtypes != null && objectSubtypes.contains(aSubType)) { + applicablePolicyConfigurationType = aPolicyConfigurationType; + } } } + if (applicablePolicyConfigurationType != null) { + return applicablePolicyConfigurationType; + } // Deprecated for (ObjectPolicyConfigurationType aPolicyConfigurationType: systemConfigurationType.getObjectTemplate()) { @@ -135,5 +157,29 @@ public static ObjectPolicyConfigurationType determineObje return null; } + + public static List determineSubTypes(PrismObject object) { + if (object == null) { + return null; + } + + // TODO: get subType (from ObjectType) + + if (object.canRepresent(UserType.class)) { + return (((UserType)object.asObjectable()).getEmployeeType()); + } + if (object.canRepresent(OrgType.class)) { + return (((OrgType)object.asObjectable()).getOrgType()); + } + if (object.canRepresent(RoleType.class)) { + List roleTypes = new ArrayList<>(1); + roleTypes.add((((RoleType)object.asObjectable()).getRoleType())); + return roleTypes; + } + if (object.canRepresent(ServiceType.class)) { + return (((ServiceType)object.asObjectable()).getServiceType()); + } + return null; + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java index b154a5e108e..64712c77b11 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java @@ -213,7 +213,7 @@ public void applySchemasAndSecurity(PrismObject object ObjectTemplateType objectTemplateType; try { - objectTemplateType = determineObjectTemplate(object.getCompileTimeClass(), AuthorizationPhaseType.REQUEST, result); + objectTemplateType = determineObjectTemplate(object, AuthorizationPhaseType.REQUEST, result); } catch (ConfigurationException | ObjectNotFoundException e) { result.recordFatalError(e); throw e; @@ -382,14 +382,29 @@ public AuthorizationDecisionType computeItemDecision(ObjectSecurityConstraints s } } + public ObjectTemplateType determineObjectTemplate(PrismObject object, AuthorizationPhaseType phase, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException { + PrismObject systemConfiguration = Utils.getSystemConfiguration(cacheRepositoryService, result); + if (systemConfiguration == null) { + return null; + } + ObjectPolicyConfigurationType objectPolicyConfiguration = ModelUtils.determineObjectPolicyConfiguration(object, systemConfiguration.asObjectable()); + if (objectPolicyConfiguration == null) { + return null; + } + ObjectReferenceType objectTemplateRef = objectPolicyConfiguration.getObjectTemplateRef(); + if (objectTemplateRef == null) { + return null; + } + PrismObject template = cacheRepositoryService.getObject(ObjectTemplateType.class, objectTemplateRef.getOid(), null, result); + return template.asObjectable(); + } - - public ObjectTemplateType determineObjectTemplate(Class objectType, AuthorizationPhaseType phase, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException { + public ObjectTemplateType determineObjectTemplate(Class objectClass, AuthorizationPhaseType phase, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException { PrismObject systemConfiguration = Utils.getSystemConfiguration(cacheRepositoryService, result); if (systemConfiguration == null) { return null; } - ObjectPolicyConfigurationType objectPolicyConfiguration = ModelUtils.determineObjectPolicyConfiguration(objectType, systemConfiguration.asObjectable()); + ObjectPolicyConfigurationType objectPolicyConfiguration = ModelUtils.determineObjectPolicyConfiguration(objectClass, null, systemConfiguration.asObjectable()); if (objectPolicyConfiguration == null) { return null; } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java index ef20509a28d..9c2ffe47f0d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java @@ -118,9 +118,10 @@ public void load(LensContext context, String activityD if (focusContext != null) { loadObjectCurrent(context, result); - loadFromSystemConfig(context, result); - context.recomputeFocus(); - + context.recomputeFocus(); + + loadFromSystemConfig(context, result); + if (FocusType.class.isAssignableFrom(context.getFocusClass())) { // this also removes the accountRef deltas loadLinkRefs((LensContext)context, task, result); @@ -378,9 +379,13 @@ private void loadFromSystemConfig(LensContext context, SystemConfigurationType systemConfigurationType = systemConfiguration.asObjectable(); if (context.getFocusContext() != null) { + PrismObject object = context.getFocusContext().getObjectAny(); if (context.getFocusContext().getObjectPolicyConfigurationType() == null) { - ObjectPolicyConfigurationType policyConfigurationType = - ModelUtils.determineObjectPolicyConfiguration(context.getFocusContext().getObjectTypeClass(), systemConfigurationType); + List subTypes = ModelUtils.determineSubTypes(object); + ObjectPolicyConfigurationType policyConfigurationType = + ModelUtils.determineObjectPolicyConfiguration(context.getFocusContext().getObjectTypeClass(), subTypes, + systemConfigurationType); + LOGGER.trace("Selected policy configuration: {}", policyConfigurationType); context.getFocusContext().setObjectPolicyConfigurationType(policyConfigurationType); } } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java index 19c69c4b5f7..877abf82260 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java @@ -80,7 +80,7 @@ public class AbstractConfiguredModelIntegrationTest extends AbstractModelIntegra protected static final String USER_TEMPLATE_FILENAME = COMMON_DIR + "/user-template.xml"; protected static final String USER_TEMPLATE_OID = "10000000-0000-0000-0000-000000000002"; - protected static final String USER_TEMPLATE_COMPLEX_FILENAME = COMMON_DIR + "/user-template-complex.xml"; + protected static final File USER_TEMPLATE_COMPLEX_FILE = new File(COMMON_DIR, "user-template-complex.xml"); protected static final String USER_TEMPLATE_COMPLEX_OID = "10000000-0000-0000-0000-000000000222"; protected static final String USER_TEMPLATE_INBOUNDS_FILENAME = COMMON_DIR + "/user-template-inbounds.xml"; diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractInitializedModelIntegrationTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractInitializedModelIntegrationTest.java index f969a7ac55b..74c28d8c360 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractInitializedModelIntegrationTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractInitializedModelIntegrationTest.java @@ -265,7 +265,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti // User Templates repoAddObjectFromFile(USER_TEMPLATE_FILENAME, ObjectTemplateType.class, initResult); - repoAddObjectFromFile(USER_TEMPLATE_COMPLEX_FILENAME, ObjectTemplateType.class, initResult); + repoAddObjectFromFile(USER_TEMPLATE_COMPLEX_FILE, ObjectTemplateType.class, initResult); repoAddObjectFromFile(USER_TEMPLATE_INBOUNDS_FILENAME, ObjectTemplateType.class, initResult); repoAddObjectFromFile(USER_TEMPLATE_COMPLEX_INCLUDE_FILENAME, ObjectTemplateType.class, initResult); repoAddObjectFromFile(USER_TEMPLATE_ORG_ASSIGNMENT_FILENAME, ObjectTemplateType.class, initResult); @@ -384,30 +384,7 @@ protected void assertDummyAccountShadowModel(PrismObject accountShad protected void setDefaultUserTemplate(String userTemplateOid) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { - - PrismObjectDefinition objectDefinition = prismContext.getSchemaRegistry() - .findObjectDefinitionByCompileTimeClass(SystemConfigurationType.class); - - Collection modifications; - - if (userTemplateOid == null) { - modifications = ReferenceDelta.createModificationReplaceCollection( - SystemConfigurationType.F_DEFAULT_USER_TEMPLATE_REF, - objectDefinition, null); - } else { - PrismReferenceValue userTemplateRefVal = new PrismReferenceValue(userTemplateOid); - modifications = ReferenceDelta.createModificationReplaceCollection( - SystemConfigurationType.F_DEFAULT_USER_TEMPLATE_REF, - objectDefinition, userTemplateRefVal); - } - - OperationResult result = new OperationResult("Aplying default user template"); - - repositoryService.modifyObject(SystemConfigurationType.class, - SystemObjectsType.SYSTEM_CONFIGURATION.value(), modifications, result); - display("Aplying default user template result", result); - result.computeStatus(); - TestUtil.assertSuccess("Aplying default user template failed (result)", result); + setDefaultObjectTemplate(UserType.COMPLEX_TYPE, userTemplateOid); } protected void assertMonkeyIslandOrgSanity() throws ObjectNotFoundException, SchemaException, SecurityViolationException, CommunicationException, ConfigurationException { diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestUserTemplate.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestUserTemplate.java index 8d8b775456d..673bc79957e 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestUserTemplate.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestUserTemplate.java @@ -63,6 +63,7 @@ import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentPolicyEnforcementType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType; import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; @@ -81,10 +82,16 @@ public class TestUserTemplate extends AbstractInitializedModelIntegrationTest { protected static final File ROLE_RASTAMAN_FILE = new File(TEST_DIR, "role-rastaman.xml"); protected static final String ROLE_RASTAMAN_OID = "81ac6b8c-225c-11e6-ab0f-87a169c85cca"; + + protected static final File USER_TEMPLATE_MAROONED_FILE = new File(TEST_DIR, "user-template-marooned.xml"); + protected static final String USER_TEMPLATE_MAROONED_OID = "766215e8-5f1e-11e6-94bb-c3b21af53235"; + private static final String ACCOUNT_STAN_USERNAME = "stan"; private static final String ACCOUNT_STAN_FULLNAME = "Stan the Salesman"; + private static final String EMPLOYEE_TYPE_MAROONED = "marooned"; + private static String jackEmployeeNumber; @Override @@ -94,7 +101,9 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti repoAddObjectFromFile(ROLE_RASTAMAN_FILE, RoleType.class, initResult); - setDefaultUserTemplate(USER_TEMPLATE_COMPLEX_OID); + repoAddObjectFromFile(USER_TEMPLATE_MAROONED_FILE, ObjectTemplateType.class, initResult); + setDefaultObjectTemplate(UserType.COMPLEX_TYPE, USER_TEMPLATE_COMPLEX_OID, initResult); + setDefaultObjectTemplate(UserType.COMPLEX_TYPE, EMPLOYEE_TYPE_MAROONED, USER_TEMPLATE_MAROONED_OID, initResult); } @Test @@ -1143,6 +1152,39 @@ public void test174ModifyUserGuybrushHonorificPrefixNone() throws Exception { assertAssignedNoRole(userAfter); } + /** + * Setting employee type to marooned. This should cause switch to different user template. + */ + @Test + public void test180ModifyUserGuybrushEmployeeTypeMarooned() throws Exception { + final String TEST_NAME = "test180ModifyUserGuybrushEmployeeTypeMarooned"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestUserTemplate.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + PrismObject userBefore = getUser(USER_GUYBRUSH_OID); + display("User before", userBefore); + assertAssignedNoRole(userBefore); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + modifyUserReplace(USER_GUYBRUSH_OID, UserType.F_EMPLOYEE_TYPE, task, result, EMPLOYEE_TYPE_MAROONED); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + PrismObject userAfter = modelService.getObject(UserType.class, USER_GUYBRUSH_OID, null, task, result); + display("User after", userAfter); + + assertEquals("Wrong costCenter", "NOCOST", userAfter.asObjectable().getCostCenter()); + + assertAssignedNoRole(userAfter); + } + @Test public void test200AddUserRapp() throws Exception { final String TEST_NAME = "test200AddUserRapp"; diff --git a/model/model-intest/src/test/resources/object-template/user-template-marooned.xml b/model/model-intest/src/test/resources/object-template/user-template-marooned.xml new file mode 100644 index 00000000000..a1b5731e36e --- /dev/null +++ b/model/model-intest/src/test/resources/object-template/user-template-marooned.xml @@ -0,0 +1,36 @@ + + + + Marooned User Template + + + costCenter + + strong + + NOCOST + + + + + 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 35c8b7110f0..3dc6bf75e94 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 @@ -1729,7 +1729,13 @@ protected void setDefaultObjectTemplate(QName objectType, String userTemplateOid TestUtil.assertSuccess("Aplying default object template failed (result)", result); } - protected void setDefaultObjectTemplate(QName objectType, String userTemplateOid, OperationResult parentResult) + + protected void setDefaultObjectTemplate(QName objectType, String objectTemplateOid, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { + setDefaultObjectTemplate(objectType, null, objectTemplateOid, parentResult); + } + + protected void setDefaultObjectTemplate(QName objectType, String subType, String objectTemplateOid, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { PrismObject systemConfig = repositoryService.getObject(SystemConfigurationType.class, @@ -1737,7 +1743,7 @@ protected void setDefaultObjectTemplate(QName objectType, String userTemplateOid PrismContainerValue oldValue = null; for (ObjectPolicyConfigurationType focusPolicyType: systemConfig.asObjectable().getDefaultObjectPolicyConfiguration()) { - if (QNameUtil.match(objectType, focusPolicyType.getType())) { + if (QNameUtil.match(objectType, focusPolicyType.getType()) && MiscUtil.equals(subType, focusPolicyType.getSubType())) { oldValue = focusPolicyType.asPrismContainerValue(); } } @@ -1749,23 +1755,26 @@ protected void setDefaultObjectTemplate(QName objectType, String userTemplateOid ((Collection)modifications).add(deleteDelta); } - ObjectPolicyConfigurationType newFocusPolicyType; - ContainerDelta addDelta; - if (oldValue == null) { - newFocusPolicyType = new ObjectPolicyConfigurationType(); - newFocusPolicyType.setType(objectType); - addDelta = ContainerDelta.createModificationAdd(SystemConfigurationType.F_DEFAULT_OBJECT_POLICY_CONFIGURATION, - SystemConfigurationType.class, prismContext, newFocusPolicyType); - } else { - PrismContainerValue newValue = oldValue.clone(); - addDelta = ContainerDelta.createModificationAdd(SystemConfigurationType.F_DEFAULT_OBJECT_POLICY_CONFIGURATION, - SystemConfigurationType.class, prismContext, newValue); - newFocusPolicyType = newValue.asContainerable(); - } - ObjectReferenceType templateRef = new ObjectReferenceType(); - templateRef.setOid(userTemplateOid); - newFocusPolicyType.setObjectTemplateRef(templateRef); - ((Collection)modifications).add(addDelta); + if (objectTemplateOid != null) { + ObjectPolicyConfigurationType newFocusPolicyType; + ContainerDelta addDelta; + if (oldValue == null) { + newFocusPolicyType = new ObjectPolicyConfigurationType(); + newFocusPolicyType.setType(objectType); + newFocusPolicyType.setSubType(subType); + addDelta = ContainerDelta.createModificationAdd(SystemConfigurationType.F_DEFAULT_OBJECT_POLICY_CONFIGURATION, + SystemConfigurationType.class, prismContext, newFocusPolicyType); + } else { + PrismContainerValue newValue = oldValue.clone(); + addDelta = ContainerDelta.createModificationAdd(SystemConfigurationType.F_DEFAULT_OBJECT_POLICY_CONFIGURATION, + SystemConfigurationType.class, prismContext, newValue); + newFocusPolicyType = newValue.asContainerable(); + } + ObjectReferenceType templateRef = new ObjectReferenceType(); + templateRef.setOid(objectTemplateOid); + newFocusPolicyType.setObjectTemplateRef(templateRef); + ((Collection)modifications).add(addDelta); + } repositoryService.modifyObject(SystemConfigurationType.class, SystemObjectsType.SYSTEM_CONFIGURATION.value(), modifications, parentResult);