Skip to content

Commit

Permalink
Add CompositeObjectDefinition#replaceDefinition
Browse files Browse the repository at this point in the history
The replaceDefinition(..) method was not supported for composite
object definitions. However, it is needed for security and schema
application code. So, sometimes it caused retrieval operations to fail.

This should resolve MID-8278.

(cherry picked from commit 5a5c857)
  • Loading branch information
mederly committed Nov 29, 2022
1 parent f23a5f0 commit cbf8f4d
Show file tree
Hide file tree
Showing 12 changed files with 284 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -321,23 +321,25 @@ public List<? extends ResourceAttributeDefinition<?>> getAttributeDefinitions()
if (auxiliaryDefinitions.isEmpty()) {
return structuralDefinition.getAttributeDefinitions();
}
List<ResourceAttributeDefinition<?>> defs =

// Adds all attribute definitions from aux OCs that are not already known.
List<ResourceAttributeDefinition<?>> allDefinitions =
new ArrayList<>(structuralDefinition.getAttributeDefinitions());
for (ResourceObjectDefinition auxiliaryObjectClassDefinition : auxiliaryDefinitions) {
for (ResourceAttributeDefinition<?> auxRAttrDef : auxiliaryObjectClassDefinition.getAttributeDefinitions()) {
boolean add = true;
for (ResourceAttributeDefinition<?> def : defs) {
boolean shouldAdd = true;
for (ResourceAttributeDefinition<?> def : allDefinitions) {
if (def.getItemName().equals(auxRAttrDef.getItemName())) {
add = false;
shouldAdd = false;
break;
}
}
if (add) {
defs.add(auxRAttrDef);
if (shouldAdd) {
allDefinitions.add(auxRAttrDef);
}
}
}
return defs;
return allDefinitions;
}

@Override
Expand Down Expand Up @@ -582,7 +584,23 @@ public CompositeObjectDefinition forLayer(@NotNull LayerType layer) {

@Override
public void replaceDefinition(@NotNull QName itemName, @Nullable ItemDefinition<?> newDefinition) {
throw new UnsupportedOperationException();

// We replace only the first occurrence. This is consistent with how we look for attributes.
// Note that this algorithm may break down if we add/delete attribute definitions afterwards.

if (structuralDefinition.containsAttributeDefinition(itemName)) {
structuralDefinition.replaceDefinition(itemName, newDefinition);
return;
}

for (ResourceObjectDefinition auxiliaryDefinition : auxiliaryDefinitions) {
if (auxiliaryDefinition.containsAttributeDefinition(itemName)) {
auxiliaryDefinition.replaceDefinition(itemName, newDefinition);
return;
}
}

throw new IllegalArgumentException("No definition for " + itemName + " to be replaced in " + this);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -809,9 +809,26 @@ public String toString() {
if (getModificationPriority() != null) {
sb.append(",P").append(getModificationPriority());
}
PropertyAccessType accessOverride = this.accessOverride;
if (accessOverride != null && !accessOverride.asPrismContainerValue().isEmpty()) {
sb.append(",AccessOverride: ");
addOverride(sb, 'R', accessOverride.isRead());
addOverride(sb, 'A', accessOverride.isAdd());
addOverride(sb, 'M', accessOverride.isModify());
}
return sb.toString();
}

private static void addOverride(StringBuilder sb, char op, Boolean value) {
if (value == null) {
sb.append(".");
} else if (value) {
sb.append(Character.toUpperCase(op));
} else {
sb.append(Character.toLowerCase(op));
}
}

/**
* Return a human readable name of this class suitable for logs.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,10 @@ <F extends ObjectType> ModelContext<F> previewChanges(
* @param object object to edit
* @return schema with correctly set constraint parts or null
*/
<O extends ObjectType> PrismObjectDefinition<O> getEditObjectDefinition(PrismObject<O> object, AuthorizationPhaseType phase, Task task, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, SecurityViolationException;
<O extends ObjectType> PrismObjectDefinition<O> getEditObjectDefinition(
PrismObject<O> object, AuthorizationPhaseType phase, Task task, OperationResult result)
throws SchemaException, ConfigurationException, ObjectNotFoundException, ExpressionEvaluationException,
CommunicationException, SecurityViolationException;

PrismObjectDefinition<ShadowType> getEditShadowDefinition(
ResourceShadowCoordinates coordinates,
Expand All @@ -136,7 +139,19 @@ PrismObjectDefinition<ShadowType> getEditShadowDefinition(
OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException,
ExpressionEvaluationException, CommunicationException, SecurityViolationException;

ResourceObjectDefinition getEditObjectClassDefinition(PrismObject<ShadowType> shadow, PrismObject<ResourceType> resource, AuthorizationPhaseType phase, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException;
/**
* Returns an object definition that reflects edit-ability of the resource object in terms of midPoint schema limitations
* and security. I.e. just like {@link #getEditShadowDefinition(ResourceShadowCoordinates, AuthorizationPhaseType, Task,
* OperationResult)} but for resource objects.
*/
ResourceObjectDefinition getEditObjectClassDefinition(
@NotNull PrismObject<ShadowType> shadow,
@NotNull PrismObject<ResourceType> resource,
AuthorizationPhaseType phase,
Task task,
OperationResult result)
throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException,
ConfigurationException, SecurityViolationException;

/**
* Returns specification of processing of given metadata item (e.g. provenance).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,8 @@ public PrismObjectDefinition<ShadowType> getEditShadowDefinition(

@Override
public ResourceObjectDefinition getEditObjectClassDefinition(
PrismObject<ShadowType> shadow,
PrismObject<ResourceType> resource,
@NotNull PrismObject<ShadowType> shadow,
@NotNull PrismObject<ResourceType> resource,
AuthorizationPhaseType phase,
Task task,
OperationResult result)
Expand All @@ -358,23 +358,36 @@ public ResourceObjectDefinition getEditObjectClassDefinition(
ResourceObjectDefinition objectDefinition = rocd.forLayer(LayerType.PRESENTATION);

// TODO: maybe we need to expose owner resolver in the interface?
ObjectSecurityConstraints securityConstraints = securityEnforcer.compileSecurityConstraints(shadow, null, task, result);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Security constrains for {}:\n{}", shadow, securityConstraints == null ? "null" : securityConstraints.debugDump());
}
ObjectSecurityConstraints securityConstraints =
securityEnforcer.compileSecurityConstraints(shadow, null, task, result);
LOGGER.trace("Security constrains for {}:\n{}", shadow, DebugUtil.debugDumpLazily(securityConstraints));
if (securityConstraints == null) {
return null;
}

ItemPath attributesPath = SchemaConstants.PATH_ATTRIBUTES;
AuthorizationDecisionType attributesReadDecision = schemaTransformer.computeItemDecision(securityConstraints, attributesPath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_GET,
securityConstraints.findAllItemsDecision(ModelAuthorizationAction.AUTZ_ACTIONS_URLS_GET, phase), phase);
AuthorizationDecisionType attributesAddDecision = schemaTransformer.computeItemDecision(securityConstraints, attributesPath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_ADD,
securityConstraints.findAllItemsDecision(ModelAuthorizationAction.ADD.getUrl(), phase), phase);
AuthorizationDecisionType attributesModifyDecision = schemaTransformer.computeItemDecision(securityConstraints, attributesPath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_MODIFY,
securityConstraints.findAllItemsDecision(ModelAuthorizationAction.MODIFY.getUrl(), phase), phase);
LOGGER.trace("Attributes container access read:{}, add:{}, modify:{}", attributesReadDecision, attributesAddDecision,
attributesModifyDecision);
AuthorizationDecisionType attributesReadDecision =
schemaTransformer.computeItemDecision(
securityConstraints,
SchemaConstants.PATH_ATTRIBUTES,
ModelAuthorizationAction.AUTZ_ACTIONS_URLS_GET,
securityConstraints.findAllItemsDecision(ModelAuthorizationAction.AUTZ_ACTIONS_URLS_GET, phase),
phase);
AuthorizationDecisionType attributesAddDecision =
schemaTransformer.computeItemDecision(
securityConstraints,
SchemaConstants.PATH_ATTRIBUTES,
ModelAuthorizationAction.AUTZ_ACTIONS_URLS_ADD,
securityConstraints.findAllItemsDecision(ModelAuthorizationAction.ADD.getUrl(), phase),
phase);
AuthorizationDecisionType attributesModifyDecision =
schemaTransformer.computeItemDecision(
securityConstraints,
SchemaConstants.PATH_ATTRIBUTES,
ModelAuthorizationAction.AUTZ_ACTIONS_URLS_MODIFY,
securityConstraints.findAllItemsDecision(ModelAuthorizationAction.MODIFY.getUrl(), phase),
phase);
LOGGER.trace("Attributes container access read:{}, add:{}, modify:{}",
attributesReadDecision, attributesAddDecision, attributesModifyDecision);

/*
* We are going to modify attribute definitions list.
Expand All @@ -386,11 +399,18 @@ public ResourceObjectDefinition getEditObjectClassDefinition(
new ArrayList<>(objectDefinition.getAttributeDefinitions());
for (ResourceAttributeDefinition<?> rAttrDef : definitionsCopy) {
ItemPath attributePath = ItemPath.create(ShadowType.F_ATTRIBUTES, rAttrDef.getItemName());
AuthorizationDecisionType attributeReadDecision = schemaTransformer.computeItemDecision(securityConstraints, attributePath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_GET, attributesReadDecision, phase);
AuthorizationDecisionType attributeAddDecision = schemaTransformer.computeItemDecision(securityConstraints, attributePath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_ADD, attributesAddDecision, phase);
AuthorizationDecisionType attributeModifyDecision = schemaTransformer.computeItemDecision(securityConstraints, attributePath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_MODIFY, attributesModifyDecision, phase);
AuthorizationDecisionType attributeReadDecision =
schemaTransformer.computeItemDecision(
securityConstraints, attributePath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_GET, attributesReadDecision, phase);
AuthorizationDecisionType attributeAddDecision =
schemaTransformer.computeItemDecision(
securityConstraints, attributePath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_ADD, attributesAddDecision, phase);
AuthorizationDecisionType attributeModifyDecision =
schemaTransformer.computeItemDecision(
securityConstraints, attributePath, ModelAuthorizationAction.AUTZ_ACTIONS_URLS_MODIFY, attributesModifyDecision, phase);
LOGGER.trace("Attribute {} access read:{}, add:{}, modify:{}", rAttrDef.getItemName(), attributeReadDecision,
attributeAddDecision, attributeModifyDecision);

if (attributeReadDecision != AuthorizationDecisionType.ALLOW
|| attributeAddDecision != AuthorizationDecisionType.ALLOW
|| attributeModifyDecision != AuthorizationDecisionType.ALLOW) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -610,26 +610,8 @@ protected void assertAssignmentsWithTargets(PrismObject<UserType> user, int expe
}
}

protected void assertAttributeFlags(ResourceObjectDefinition rOcDef,
QName attrName, boolean expectedRead, boolean expectedAdd, boolean expectedModify) {
ResourceAttributeDefinition<?> rAttrDef = rOcDef.findAttributeDefinition(attrName);
assertNotNull(rAttrDef);
assertEquals("Wrong readability flag for " + attrName, expectedRead, rAttrDef.canRead());
assertEquals("Wrong addition flag for " + attrName, expectedAdd, rAttrDef.canAdd());
assertEquals("Wrong modification flag for " + attrName, expectedModify, rAttrDef.canModify());
}

protected void assertAttributeFlags(ResourceObjectClassDefinition rOcDef,
QName attrName, boolean expectedRead, boolean expectedAdd, boolean expectedModify) {
ResourceAttributeDefinition<?> rAttrDef = rOcDef.findAttributeDefinition(attrName);
assertNotNull(rAttrDef);
assertEquals("Wrong readability flag for " + attrName, expectedRead, rAttrDef.canRead());
assertEquals("Wrong addition flag for " + attrName, expectedAdd, rAttrDef.canAdd());
assertEquals("Wrong modification flag for " + attrName, expectedModify, rAttrDef.canModify());
}

protected void cleanupAutzTest(String userOid
) throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException,
protected void cleanupAutzTest(String userOid)
throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException,
CommunicationException, ConfigurationException, ObjectAlreadyExistsException,
PolicyViolationException, SecurityViolationException, IOException {
cleanupAutzTest(userOid, 0);
Expand Down

0 comments on commit cbf8f4d

Please sign in to comment.