/** * Copyright (c) 2014-2016 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.model.impl.controller; import java.util.*; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.schema.SearchResultList; import com.evolveum.midpoint.schema.internals.InternalsConfig; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import org.apache.commons.lang.Validate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.evolveum.midpoint.common.crypto.CryptoUtil; import com.evolveum.midpoint.model.api.ModelAuthorizationAction; import com.evolveum.midpoint.model.common.SystemObjectCache; import com.evolveum.midpoint.model.impl.util.Utils; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.xml.XsdTypeMapper; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; import com.evolveum.midpoint.security.api.ObjectSecurityConstraints; import com.evolveum.midpoint.security.api.SecurityEnforcer; import com.evolveum.midpoint.security.api.SecurityUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.AuthorizationException; import com.evolveum.midpoint.util.exception.ConfigurationException; 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.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationDecisionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationPhaseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.LayerType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectPolicyConfigurationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateItemDefinitionType; 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.OperationResultStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType; import com.evolveum.midpoint.xml.ns._public.common.common_3.PropertyAccessType; import com.evolveum.midpoint.xml.ns._public.common.common_3.PropertyLimitationsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ReportType; 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.SystemConfigurationType; import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; import javax.xml.namespace.QName; /** * Transforms the schema and objects by applying security constraints, * object template schema refinements, etc. * * @author semancik */ @Component public class SchemaTransformer { private static final Trace LOGGER = TraceManager.getTrace(SchemaTransformer.class); @Autowired(required = true) @Qualifier("cacheRepositoryService") private transient RepositoryService cacheRepositoryService; @Autowired(required = true) private SecurityEnforcer securityEnforcer; @Autowired(required = true) private SystemObjectCache systemObjectCache; @Autowired private PrismContext prismContext; // TODO why are the following two methods distinct? Clarify their names. public <T extends ObjectType> void applySchemasAndSecurityToObjectTypes(List<T> objectTypes, GetOperationOptions options, AuthorizationPhaseType phase, Task task, OperationResult result) throws SecurityViolationException, SchemaException, ConfigurationException, ObjectNotFoundException { for (int i = 0; i < objectTypes.size(); i++) { PrismObject<T> object = (PrismObject<T>) objectTypes.get(i).asPrismObject(); object = object.cloneIfImmutable(); objectTypes.set(i, object.asObjectable()); applySchemasAndSecurity(object, options, phase, task, result); } } public <T extends ObjectType> void applySchemasAndSecurityToObjects(List<PrismObject<T>> objects, GetOperationOptions options, AuthorizationPhaseType phase, Task task, OperationResult result) throws SecurityViolationException, SchemaException { for (int i = 0; i < objects.size(); i++) { PrismObject<T> object = objects.get(i); object = object.cloneIfImmutable(); objects.set(i, object); applySchemaAndSecurityToObject(object, options, phase, task); } } // Expecting that C is a direct child of T. // Expecting that container values point to their respective parents (in order to evaluate the security!) public <C extends Containerable, T extends ObjectType> SearchResultList<C> applySchemasAndSecurityToContainers(SearchResultList<C> originalResultList, Class<T> parentObjectType, QName childItemName, GetOperationOptions options, AuthorizationPhaseType phase, Task task, OperationResult result) throws SecurityViolationException, SchemaException, ObjectNotFoundException, ConfigurationException { List<C> newValues = new ArrayList<>(); Map<PrismObject<T>,Object> processedParents = new IdentityHashMap<>(); final ItemPath childItemPath = new ItemPath(childItemName); for (C value: originalResultList) { Long originalId = value.asPrismContainerValue().getId(); if (originalId == null) { throw new SchemaException("No ID in container value " + value); } PrismObject<T> parent = ObjectTypeUtil.getParentObject(value); boolean wasProcessed; if (parent != null) { wasProcessed = processedParents.containsKey(parent); } else { // temporary solution TODO reconsider parent = prismContext.createObject(parentObjectType); PrismContainer<C> childContainer = parent.findOrCreateItem(childItemPath, PrismContainer.class); childContainer.add(value.asPrismContainerValue()); wasProcessed = false; } if (!wasProcessed) { // TODO what if parent is immutable? applySchemasAndSecurity(parent, options, phase, task, result); processedParents.put(parent, null); } PrismContainer<C> updatedChildContainer = parent.findContainer(childItemPath); if (updatedChildContainer != null) { PrismContainerValue<C> updatedChildValue = updatedChildContainer.getValue(originalId); if (updatedChildValue != null) { newValues.add(updatedChildValue.asContainerable()); } } } return new SearchResultList<>(newValues, originalResultList.getMetadata()); } protected <T extends ObjectType> void applySchemaAndSecurityToObject(PrismObject<T> object, GetOperationOptions options, AuthorizationPhaseType phase, Task task) { OperationResult subresult = new OperationResult(SchemaTransformer.class.getName()+".applySchemasAndSecurityToObjects"); try { applySchemasAndSecurity(object, options, phase, task, subresult); } catch (IllegalArgumentException|IllegalStateException|SchemaException |SecurityViolationException |ConfigurationException |ObjectNotFoundException e) { LOGGER.error("Error post-processing object {}: {}", new Object[]{object, e.getMessage(), e}); OperationResultType fetchResult = object.asObjectable().getFetchResult(); if (fetchResult == null) { fetchResult = subresult.createOperationResultType(); object.asObjectable().setFetchResult(fetchResult); } else { fetchResult.getPartialResults().add(subresult.createOperationResultType()); } fetchResult.setStatus(OperationResultStatusType.FATAL_ERROR); } } /** * Validate the objects, apply security to the object definition, remove any non-visible properties (security), * apply object template definitions and so on. This method is called for * any object that is returned from the Model Service. */ public <O extends ObjectType> void applySchemasAndSecurity(PrismObject<O> object, GetOperationOptions rootOptions, AuthorizationPhaseType phase, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ConfigurationException, ObjectNotFoundException { OperationResult result = parentResult.createMinorSubresult(SchemaTransformer.class.getName()+".applySchemasAndSecurity"); validateObject(object, rootOptions, result); PrismObjectDefinition<O> objectDefinition = object.deepCloneDefinition(true); ObjectSecurityConstraints securityConstraints; try { securityConstraints = securityEnforcer.compileSecurityConstraints(object, null); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Security constrains for {}:\n{}", object, securityConstraints==null?"null":securityConstraints.debugDump()); } if (securityConstraints == null) { SecurityUtil.logSecurityDeny(object, "because no security constraints are defined (default deny)"); throw new AuthorizationException("Access denied"); } } catch (SecurityViolationException | SchemaException | RuntimeException e) { result.recordFatalError(e); throw e; } if (phase == null) { applySchemasAndSecurityPhase(object, securityConstraints, objectDefinition, rootOptions, AuthorizationPhaseType.REQUEST, task, result); applySchemasAndSecurityPhase(object, securityConstraints, objectDefinition, rootOptions, AuthorizationPhaseType.EXECUTION, task, result); } else { applySchemasAndSecurityPhase(object, securityConstraints, objectDefinition, rootOptions, phase, task, result); } ObjectTemplateType objectTemplateType; try { objectTemplateType = determineObjectTemplate(object, AuthorizationPhaseType.REQUEST, result); } catch (ConfigurationException | ObjectNotFoundException e) { result.recordFatalError(e); throw e; } applyObjectTemplateToObject(object, objectTemplateType, result); result.computeStatus(); result.recordSuccessIfUnknown(); } private <O extends ObjectType> void applySchemasAndSecurityPhase(PrismObject<O> object, ObjectSecurityConstraints securityConstraints, PrismObjectDefinition<O> objectDefinition, GetOperationOptions rootOptions, AuthorizationPhaseType phase, Task task, OperationResult result) throws SchemaException, SecurityViolationException, ConfigurationException, ObjectNotFoundException { Validate.notNull(phase); try { AuthorizationDecisionType globalReadDecision = securityConstraints.getActionDecision(ModelAuthorizationAction.READ.getUrl(), phase); if (globalReadDecision == AuthorizationDecisionType.DENY) { // shortcut SecurityUtil.logSecurityDeny(object, "because the authorization denies access"); throw new AuthorizationException("Access denied"); } AuthorizationDecisionType globalAddDecision = securityConstraints.getActionDecision(ModelAuthorizationAction.ADD.getUrl(), phase); AuthorizationDecisionType globalModifyDecision = securityConstraints.getActionDecision(ModelAuthorizationAction.MODIFY.getUrl(), phase); applySecurityConstraints((List)object.getValue().getItems(), securityConstraints, globalReadDecision, globalAddDecision, globalModifyDecision, phase); if (object.isEmpty()) { // let's make it explicit SecurityUtil.logSecurityDeny(object, "because the subject has not access to any item"); throw new AuthorizationException("Access denied"); } applySecurityConstraintsItemDef(objectDefinition, ItemPath.EMPTY_PATH, securityConstraints, globalReadDecision, globalAddDecision, globalModifyDecision, phase); } catch (SecurityViolationException | RuntimeException e) { result.recordFatalError(e); throw e; } } public void applySecurityConstraints(List<Item<?,?>> items, ObjectSecurityConstraints securityConstraints, AuthorizationDecisionType defaultReadDecision, AuthorizationDecisionType defaultAddDecision, AuthorizationDecisionType defaultModifyDecision, AuthorizationPhaseType phase) { LOGGER.trace("applySecurityConstraints(items): items={}, phase={}, defaults R={}, A={}, M={}", items, phase, defaultReadDecision, defaultAddDecision, defaultModifyDecision); if (items == null) { return; } Iterator<Item<?,?>> iterator = items.iterator(); while (iterator.hasNext()) { Item<?,?> item = iterator.next(); ItemPath itemPath = item.getPath(); AuthorizationDecisionType itemReadDecision = computeItemDecision(securityConstraints, itemPath, ModelAuthorizationAction.READ.getUrl(), defaultReadDecision, phase); AuthorizationDecisionType itemAddDecision = computeItemDecision(securityConstraints, itemPath, ModelAuthorizationAction.ADD.getUrl(), defaultReadDecision, phase); AuthorizationDecisionType itemModifyDecision = computeItemDecision(securityConstraints, itemPath, ModelAuthorizationAction.MODIFY.getUrl(), defaultReadDecision, phase); LOGGER.trace("applySecurityConstraints(item): {}: decisions R={}, A={}, M={}", itemPath, itemReadDecision, itemAddDecision, itemModifyDecision); ItemDefinition<?> itemDef = item.getDefinition(); if (itemDef != null) { if (itemReadDecision != AuthorizationDecisionType.ALLOW) { ((ItemDefinitionImpl) itemDef).setCanRead(false); } if (itemAddDecision != AuthorizationDecisionType.ALLOW) { ((ItemDefinitionImpl) itemDef).setCanAdd(false); } if (itemModifyDecision != AuthorizationDecisionType.ALLOW) { ((ItemDefinitionImpl) itemDef).setCanModify(false); } } if (item instanceof PrismContainer<?>) { if (itemReadDecision == AuthorizationDecisionType.DENY) { // Explicitly denied access to the entire container iterator.remove(); } else { // No explicit decision (even ALLOW is not final here as something may be denied deeper inside) AuthorizationDecisionType subDefaultReadDecision = defaultReadDecision; if (itemReadDecision == AuthorizationDecisionType.ALLOW) { // This means allow to all subitems unless otherwise denied. subDefaultReadDecision = AuthorizationDecisionType.ALLOW; } boolean itemWasEmpty = item.isEmpty(); // to prevent removal of originally empty items List<? extends PrismContainerValue<?>> values = ((PrismContainer<?>)item).getValues(); Iterator<? extends PrismContainerValue<?>> vi = values.iterator(); while (vi.hasNext()) { PrismContainerValue<?> cval = vi.next(); List<Item<?,?>> subitems = cval.getItems(); if (subitems != null && !subitems.isEmpty()) { // second condition is to prevent removal of originally empty values applySecurityConstraints(subitems, securityConstraints, subDefaultReadDecision, itemAddDecision, itemModifyDecision, phase); if (subitems.isEmpty()) { vi.remove(); } } } if (!itemWasEmpty && item.isEmpty()) { iterator.remove(); } } } else { if (itemReadDecision == AuthorizationDecisionType.DENY || (itemReadDecision == null && defaultReadDecision == null)) { iterator.remove(); } } } } public <D extends ItemDefinition> void applySecurityConstraints(D itemDefinition, ObjectSecurityConstraints securityConstraints, AuthorizationPhaseType phase) { if (phase == null) { applySecurityConstraintsPhase(itemDefinition, securityConstraints, AuthorizationPhaseType.REQUEST); applySecurityConstraintsPhase(itemDefinition, securityConstraints, AuthorizationPhaseType.EXECUTION); } else { applySecurityConstraintsPhase(itemDefinition, securityConstraints, phase); } } private <D extends ItemDefinition> void applySecurityConstraintsPhase(D itemDefinition, ObjectSecurityConstraints securityConstraints, AuthorizationPhaseType phase) { Validate.notNull(phase); AuthorizationDecisionType defaultReadDecision = securityConstraints.getActionDecision(ModelAuthorizationAction.READ.getUrl(), phase); AuthorizationDecisionType defaultAddDecision = securityConstraints.getActionDecision(ModelAuthorizationAction.ADD.getUrl(), phase); AuthorizationDecisionType defaultModifyDecision = securityConstraints.getActionDecision(ModelAuthorizationAction.MODIFY.getUrl(), phase); LOGGER.trace("applySecurityConstraints(itemDefs): def={}, phase={}, defaults R={}, A={}, M={}", new Object[]{itemDefinition, phase, defaultReadDecision, defaultAddDecision, defaultModifyDecision}); applySecurityConstraintsItemDef(itemDefinition, ItemPath.EMPTY_PATH, securityConstraints, defaultReadDecision, defaultAddDecision, defaultModifyDecision, phase); } private <D extends ItemDefinition> void applySecurityConstraintsItemDef(D itemDefinition, ItemPath itemPath, ObjectSecurityConstraints securityConstraints, AuthorizationDecisionType defaultReadDecision, AuthorizationDecisionType defaultAddDecision, AuthorizationDecisionType defaultModifyDecision, AuthorizationPhaseType phase) { AuthorizationDecisionType readDecision = computeItemDecision(securityConstraints, itemPath, ModelAuthorizationAction.READ.getUrl(), defaultReadDecision, phase); AuthorizationDecisionType addDecision = computeItemDecision(securityConstraints, itemPath, ModelAuthorizationAction.ADD.getUrl(), defaultAddDecision, phase); AuthorizationDecisionType modifyDecision = computeItemDecision(securityConstraints, itemPath, ModelAuthorizationAction.MODIFY.getUrl(), defaultModifyDecision, phase); boolean anySubElementRead = false; boolean anySubElementAdd = false; boolean anySubElementModify = false; if (itemDefinition instanceof PrismContainerDefinition<?>) { PrismContainerDefinition<?> containerDefinition = (PrismContainerDefinition<?>)itemDefinition; List<? extends ItemDefinition> subDefinitions = ((PrismContainerDefinition<?>)containerDefinition).getDefinitions(); for (ItemDefinition subDef: subDefinitions) { if (!subDef.getName().equals(ShadowType.F_ATTRIBUTES)) { // Shadow attributes have special handling applySecurityConstraintsItemDef(subDef, new ItemPath(itemPath, subDef.getName()), securityConstraints, readDecision, addDecision, modifyDecision, phase); } if (subDef.canRead()) { anySubElementRead = true; } if (subDef.canAdd()) { anySubElementAdd = true; } if (subDef.canModify()) { anySubElementModify = true; } } } LOGGER.trace("applySecurityConstraints(itemDef): {}: decisions R={}, A={}, M={}; subelements R={}, A={}, M={}", itemPath, readDecision, addDecision, modifyDecision, anySubElementRead, anySubElementAdd, anySubElementModify); if (readDecision != AuthorizationDecisionType.ALLOW) { ((ItemDefinitionImpl) itemDefinition).setCanRead(false); } if (addDecision != AuthorizationDecisionType.ALLOW) { ((ItemDefinitionImpl) itemDefinition).setCanAdd(false); } if (modifyDecision != AuthorizationDecisionType.ALLOW) { ((ItemDefinitionImpl) itemDefinition).setCanModify(false); } if (anySubElementRead) { ((ItemDefinitionImpl) itemDefinition).setCanRead(true); } if (anySubElementAdd) { ((ItemDefinitionImpl) itemDefinition).setCanAdd(true); } if (anySubElementModify) { ((ItemDefinitionImpl) itemDefinition).setCanModify(true); } } public AuthorizationDecisionType computeItemDecision(ObjectSecurityConstraints securityConstraints, ItemPath itemPath, String actionUrl, AuthorizationDecisionType defaultDecision, AuthorizationPhaseType phase) { AuthorizationDecisionType explicitDecision = securityConstraints.findItemDecision(itemPath, actionUrl, phase); // LOGGER.trace("Explicit decision for {}: {}", itemPath, explicitDecision); if (explicitDecision != null) { return explicitDecision; } else { return defaultDecision; } } public <O extends ObjectType> ObjectTemplateType determineObjectTemplate(PrismObject<O> object, AuthorizationPhaseType phase, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException { PrismObject<SystemConfigurationType> systemConfiguration = systemObjectCache.getSystemConfiguration(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<ObjectTemplateType> template = cacheRepositoryService.getObject(ObjectTemplateType.class, objectTemplateRef.getOid(), null, result); return template.asObjectable(); } public <O extends ObjectType> ObjectTemplateType determineObjectTemplate(Class<O> objectClass, AuthorizationPhaseType phase, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException { PrismObject<SystemConfigurationType> systemConfiguration = systemObjectCache.getSystemConfiguration(result); if (systemConfiguration == null) { return null; } ObjectPolicyConfigurationType objectPolicyConfiguration = ModelUtils.determineObjectPolicyConfiguration(objectClass, null, systemConfiguration.asObjectable()); if (objectPolicyConfiguration == null) { return null; } ObjectReferenceType objectTemplateRef = objectPolicyConfiguration.getObjectTemplateRef(); if (objectTemplateRef == null) { return null; } PrismObject<ObjectTemplateType> template = cacheRepositoryService.getObject(ObjectTemplateType.class, objectTemplateRef.getOid(), null, result); return template.asObjectable(); } public <O extends ObjectType> void applyObjectTemplateToDefinition(PrismObjectDefinition<O> objectDefinition, ObjectTemplateType objectTemplateType, OperationResult result) throws ObjectNotFoundException, SchemaException { if (objectTemplateType == null) { return; } for (ObjectReferenceType includeRef: objectTemplateType.getIncludeRef()) { PrismObject<ObjectTemplateType> subTemplate = cacheRepositoryService.getObject(ObjectTemplateType.class, includeRef.getOid(), null, result); applyObjectTemplateToDefinition(objectDefinition, subTemplate.asObjectable(), result); } for (ObjectTemplateItemDefinitionType templateItemDefType: objectTemplateType.getItem()) { ItemPathType ref = templateItemDefType.getRef(); if (ref == null) { throw new SchemaException("No 'ref' in item definition in "+objectTemplateType); } ItemPath itemPath = ref.getItemPath(); ItemDefinition itemDef = objectDefinition.findItemDefinition(itemPath); if (itemDef != null) { applyObjectTemplateItem(itemDef, templateItemDefType, "item " + itemPath + " in object type " + objectDefinition.getTypeName() + " as specified in item definition in " + objectTemplateType); } else { OperationResult subResult = result.createMinorSubresult(SchemaTransformer.class.getName() + ".applyObjectTemplateToDefinition"); subResult.recordPartialError("No definition for item " + itemPath + " in object type " + objectDefinition.getTypeName() + " as specified in item definition in " + objectTemplateType); continue; } } } private <O extends ObjectType> void applyObjectTemplateToObject(PrismObject<O> object, ObjectTemplateType objectTemplateType, OperationResult result) throws ObjectNotFoundException, SchemaException { if (objectTemplateType == null) { return; } for (ObjectReferenceType includeRef: objectTemplateType.getIncludeRef()) { PrismObject<ObjectTemplateType> subTemplate = cacheRepositoryService.getObject(ObjectTemplateType.class, includeRef.getOid(), null, result); applyObjectTemplateToObject(object, subTemplate.asObjectable(), result); } for (ObjectTemplateItemDefinitionType templateItemDefType: objectTemplateType.getItem()) { ItemPathType ref = templateItemDefType.getRef(); if (ref == null) { throw new SchemaException("No 'ref' in item definition in "+objectTemplateType); } ItemPath itemPath = ref.getItemPath(); ItemDefinition itemDefFromObject = object.getDefinition().findItemDefinition(itemPath); if (itemDefFromObject != null) { applyObjectTemplateItem(itemDefFromObject, templateItemDefType, "item " + itemPath + " in " + object + " as specified in item definition in " + objectTemplateType); } else { OperationResult subResult = result.createMinorSubresult(SchemaTransformer.class.getName() + ".applyObjectTemplateToObject"); subResult.recordPartialError("No definition for item " + itemPath + " in " + object + " as specified in item definition in " + objectTemplateType); continue; } Item<?, ?> item = object.findItem(itemPath); if (item != null) { ItemDefinition itemDef = item.getDefinition(); if (itemDef != itemDefFromObject) { applyObjectTemplateItem(itemDef, templateItemDefType, "item "+itemPath+" in " + object + " as specified in item definition in "+objectTemplateType); } } } } private <IV extends PrismValue,ID extends ItemDefinition> void applyObjectTemplateItem(ID itemDef, ObjectTemplateItemDefinitionType templateItemDefType, String desc) throws SchemaException { if (itemDef == null) { throw new SchemaException("No definition for "+desc); } String displayName = templateItemDefType.getDisplayName(); if (displayName != null) { ((ItemDefinitionImpl) itemDef).setDisplayName(displayName); } Integer displayOrder = templateItemDefType.getDisplayOrder(); if (displayOrder != null) { ((ItemDefinitionImpl) itemDef).setDisplayOrder(displayOrder); } Boolean emphasized = templateItemDefType.isEmphasized(); if (emphasized != null) { ((ItemDefinitionImpl) itemDef).setEmphasized(emphasized); } List<PropertyLimitationsType> limitations = templateItemDefType.getLimitations(); if (limitations != null) { PropertyLimitationsType limitationsType = MiscSchemaUtil.getLimitationsType(limitations, LayerType.PRESENTATION); if (limitationsType != null) { if (limitationsType.getMinOccurs() != null) { ((ItemDefinitionImpl) itemDef).setMinOccurs(XsdTypeMapper.multiplicityToInteger(limitationsType.getMinOccurs())); } if (limitationsType.getMaxOccurs() != null) { ((ItemDefinitionImpl) itemDef).setMaxOccurs(XsdTypeMapper.multiplicityToInteger(limitationsType.getMaxOccurs())); } if (limitationsType.isIgnore() != null) { ((ItemDefinitionImpl) itemDef).setIgnored(limitationsType.isIgnore()); } PropertyAccessType accessType = limitationsType.getAccess(); if (accessType != null) { if (accessType.isAdd() != null) { ((ItemDefinitionImpl) itemDef).setCanAdd(accessType.isAdd()); } if (accessType.isModify() != null) { ((ItemDefinitionImpl) itemDef).setCanModify(accessType.isModify()); } if (accessType.isRead() != null) { ((ItemDefinitionImpl) itemDef).setCanRead(accessType.isRead()); } } } } ObjectReferenceType valueEnumerationRef = templateItemDefType.getValueEnumerationRef(); if (valueEnumerationRef != null) { PrismReferenceValue valueEnumerationRVal = MiscSchemaUtil.objectReferenceTypeToReferenceValue(valueEnumerationRef); ((ItemDefinitionImpl) itemDef).setValueEnumerationRef(valueEnumerationRVal); } } private <T extends ObjectType> void validateObject(PrismObject<T> object, GetOperationOptions options, OperationResult result) { try { if (InternalsConfig.readEncryptionChecks) { CryptoUtil.checkEncrypted(object); } if (!InternalsConfig.consistencyChecks) { return; } Class<T> type = object.getCompileTimeClass(); boolean tolerateRaw = GetOperationOptions.isTolerateRawData(options); if (type == ResourceType.class || ShadowType.class.isAssignableFrom(type) || type == ReportType.class) { // We tolerate raw values for resource and shadows in case the user has requested so tolerateRaw = GetOperationOptions.isRaw(options); } if (hasError(object, result)) { // If there is an error then the object might not be complete. // E.g. we do not have a complete dynamic schema to apply to the object // Tolerate some raw meat in that case. tolerateRaw = true; } if (InternalsConfig.consistencyChecks) { object.checkConsistence(true, !tolerateRaw, ConsistencyCheckScope.THOROUGH); } } catch (RuntimeException e) { result.recordFatalError(e); throw e; } } private <T extends ObjectType> boolean hasError(PrismObject<T> object, OperationResult result) { if (result != null && result.isError()) { // actually, result is pretty tiny here - does not include object fetch/get operation return true; } OperationResultType fetchResult = object.asObjectable().getFetchResult(); if (fetchResult != null && (fetchResult.getStatus() == OperationResultStatusType.FATAL_ERROR || fetchResult.getStatus() == OperationResultStatusType.PARTIAL_ERROR)) { return true; } return false; } }