From 1471bba52e363f81feabbec6f997507d8a7655fb Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Fri, 22 Sep 2023 08:56:16 +0200 Subject: [PATCH] Check authorizations in some midpoint.* methods When using methods countAccounts, getObjectsInConflictOnPropertyValue, and isUniquePropertyValue we originally did not check authorizations of the currently logged-in user. This is now fixed. Also, remaining methods that avoid authorization checks were marked as such in the API docs. Note that this is an incompatible change, so users are advised to check their configurations. This resolves MID-6241. --- .../model/api/expr/MidpointFunctions.java | 2 + .../impl/expr/MidpointFunctionsImpl.java | 127 +++++++++--------- 2 files changed, 64 insertions(+), 65 deletions(-) diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/expr/MidpointFunctions.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/expr/MidpointFunctions.java index bdae62aebcb..4f4edc14402 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/expr/MidpointFunctions.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/expr/MidpointFunctions.java @@ -861,6 +861,7 @@ int countObjects(Class type, ObjectQuery query) List toList(String... s); + /** Uses repository service directly, bypassing authorization checking. */ long getSequenceCounter(String sequenceOid) throws ObjectNotFoundException, SchemaException; Collection getManagersOids(UserType user) throws SchemaException, ObjectNotFoundException, SecurityViolationException; @@ -877,6 +878,7 @@ Collection getManagersOidsExceptUser(@NotNull Collection getManagers(UserType user, String orgType, boolean allowSelf) throws SchemaException, ObjectNotFoundException, SecurityViolationException; + /** Uses repository service directly, bypassing authorization checking. */ UserType getUserByOid(String oid) throws ObjectNotFoundException, SchemaException; // todo here we could select "functional" org.units in order to filter out e.g. project managers from the list of managers diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java index ba32f70b7cc..63191d22c1f 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java @@ -21,6 +21,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.Serial; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @@ -521,6 +522,7 @@ private boolean willFocusBeActive() { @NotNull private static LensFocusContext getFocusContextRequired() { + //noinspection unchecked return (LensFocusContext) ModelExpressionThreadLocalHolder.getLensContextRequired().getFocusContextRequired(); } @@ -699,8 +701,9 @@ public Integer countAccounts(String resourceOid, QName attributeName, T attr throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { OperationResult result = getCurrentResult(CLASS_DOT + "countAccounts"); - ResourceType resourceType = modelObjectResolver.getObjectSimple(ResourceType.class, resourceOid, null, null, result); - return countAccounts(resourceType, attributeName, attributeValue, getCurrentTask(), result); + // Intentionally ignoring authorizations, as we are not interested in the resource as such. + ResourceType resource = modelObjectResolver.getObjectSimple(ResourceType.class, resourceOid, null, null, result); + return countAccounts(resource, attributeName, attributeValue, getCurrentTask(), result); } @Override @@ -725,12 +728,12 @@ private QName getRiAttributeQName(String attributeName) { return new QName(MidPointConstants.NS_RI, attributeName); } - private Integer countAccounts(ResourceType resourceType, QName attributeName, T attributeValue, Task task, - OperationResult result) + private Integer countAccounts( + ResourceType resource, QName attributeName, T attributeValue, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - ObjectQuery query = createAttributeQuery(resourceType, attributeName, attributeValue); - return modelObjectResolver.countObjects(ShadowType.class, query, null, task, result); + ObjectQuery query = createAttributeQuery(resource, attributeName, attributeValue); + return modelService.countObjects(ShadowType.class, query, null, task, result); } @Override @@ -743,45 +746,49 @@ public boolean isUniquePropertyValue(ObjectType objectType, String propertyP return isUniquePropertyValue(objectType, propertyPath, propertyValue, getCurrentTask(), result); } - private boolean isUniquePropertyValue(final ObjectType objectType, ItemPath propertyPath, T propertyValue, Task task, - OperationResult result) + private boolean isUniquePropertyValue( + ObjectType object, ItemPath propertyPath, T propertyValue, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - List conflictingObjects = getObjectsInConflictOnPropertyValue(objectType, propertyPath, - propertyValue, null, false, task, result); + List conflictingObjects = getObjectsInConflictOnPropertyValue( + object, propertyPath, propertyValue, null, false, task, result); return conflictingObjects.isEmpty(); } @Override - public List getObjectsInConflictOnPropertyValue(O objectType, String propertyPathString, - T propertyValue, boolean getAllConflicting) + public List getObjectsInConflictOnPropertyValue( + O object, String propertyPathString, T propertyValue, boolean getAllConflicting) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - return getObjectsInConflictOnPropertyValue(objectType, propertyPathString, propertyValue, + return getObjectsInConflictOnPropertyValue(object, propertyPathString, propertyValue, PrismConstants.DEFAULT_MATCHING_RULE_NAME.getLocalPart(), getAllConflicting); } - public List getObjectsInConflictOnPropertyValue(O objectType, String propertyPathString, - T propertyValue, String matchingRuleName, boolean getAllConflicting) + private List getObjectsInConflictOnPropertyValue( + O object, String propertyPathString, T propertyValue, String matchingRuleName, boolean getAllConflicting) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { Validate.notEmpty(propertyPathString, "Empty property path"); OperationResult result = getCurrentResult(MidpointFunctions.class.getName() + "getObjectsInConflictOnPropertyValue"); ItemPath propertyPath = prismContext.itemPathParser().asItemPath(propertyPathString); QName matchingRuleQName = new QName(matchingRuleName); // no namespace for now - return getObjectsInConflictOnPropertyValue(objectType, propertyPath, propertyValue, matchingRuleQName, getAllConflicting, + return getObjectsInConflictOnPropertyValue(object, propertyPath, propertyValue, matchingRuleQName, getAllConflicting, getCurrentTask(), result); } - private List getObjectsInConflictOnPropertyValue(final O objectType, ItemPath propertyPath, - T propertyValue, QName matchingRule, final boolean getAllConflicting, Task task, OperationResult result) + private List getObjectsInConflictOnPropertyValue( + @NotNull O object, + @NotNull ItemPath propertyPath, + @NotNull T propertyValue, + QName matchingRule, + boolean getAllConflicting, + Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - Validate.notNull(objectType, "Null object"); Validate.notNull(propertyPath, "Null property path"); - Validate.notNull(propertyValue, "Null property value"); - PrismPropertyDefinition propertyDefinition = objectType.asPrismObject().getDefinition() - .findPropertyDefinition(propertyPath); + Validate.notNull(propertyValue, "Null property value"); // we must check this explicitly + PrismPropertyDefinition propertyDefinition = + object.asPrismObject().getDefinition().findPropertyDefinition(propertyPath); if (matchingRule == null) { if (propertyDefinition != null && PolyStringType.COMPLEX_TYPE.equals(propertyDefinition.getTypeName())) { matchingRule = PrismConstants.POLY_STRING_ORIG_MATCHING_RULE_NAME; @@ -789,78 +796,67 @@ private List getObjectsInConflictOnPropertyValue(fi matchingRule = PrismConstants.DEFAULT_MATCHING_RULE_NAME; } } - ObjectQuery query = prismContext.queryFor(objectType.getClass()) + ObjectQuery query = prismContext.queryFor(object.getClass()) .item(propertyPath, propertyDefinition).eq(propertyValue).matching(matchingRule) .build(); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Determining uniqueness of property {} using query:\n{}", propertyPath, query.debugDump()); - } + LOGGER.trace("Determining uniqueness of property {} using query:\n{}", propertyPath, query.debugDumpLazily()); final List conflictingObjects = new ArrayList<>(); - ResultHandler handler = (object, parentResult) -> { - if (objectType.getOid() == null) { - // We have found a conflicting object - conflictingObjects.add(object.asObjectable()); - return getAllConflicting; + ResultHandler handler = (foundObject, lResult) -> { + if (object.getOid() != null && object.getOid().equals(foundObject.getOid())) { + // We have found ourselves. No conflict (yet). Just go on. + return true; } else { - if (objectType.getOid().equals(object.getOid())) { - // We have found ourselves. No conflict (yet). Just go on. - return true; - } else { - // We have found someone else. Conflict. - conflictingObjects.add(object.asObjectable()); - return getAllConflicting; - } + // We have found someone else. Conflict. + conflictingObjects.add(foundObject.asObjectable()); + return getAllConflicting; } }; - //noinspection unchecked,rawtypes - modelObjectResolver.searchIterative((Class) objectType.getClass(), query, null, handler, task, result); + //noinspection unchecked + modelService.searchObjectsIterative((Class) object.getClass(), query, handler, null, task, result); + LOGGER.trace("Found {} conflicting objects", conflictingObjects.size()); return conflictingObjects; } @Override - public boolean isUniqueAccountValue(ResourceType resourceType, ShadowType shadowType, String attributeName, - T attributeValue) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, + public boolean isUniqueAccountValue( + ResourceType resource, ShadowType shadow, String attributeName, T attributeValue) + throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { Validate.notEmpty(attributeName, "Empty attribute name"); OperationResult result = getCurrentResult(MidpointFunctions.class.getName() + "isUniqueAccountValue"); QName attributeQName = getRiAttributeQName(attributeName); - return isUniqueAccountValue(resourceType, shadowType, attributeQName, attributeValue, getCurrentTask(), result); + return isUniqueAccountValue(resource, shadow, attributeQName, attributeValue, getCurrentTask(), result); } - private boolean isUniqueAccountValue(ResourceType resourceType, final ShadowType shadowType, - QName attributeName, T attributeValue, Task task, OperationResult result) + private boolean isUniqueAccountValue( + ResourceType resource, ShadowType shadow, QName attributeName, T attributeValue, + Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - Validate.notNull(resourceType, "Null resource"); - Validate.notNull(shadowType, "Null shadow"); + Validate.notNull(resource, "Null resource"); + Validate.notNull(shadow, "Null shadow"); Validate.notNull(attributeName, "Null attribute name"); Validate.notNull(attributeValue, "Null attribute value"); - ObjectQuery query = createAttributeQuery(resourceType, attributeName, attributeValue); + ObjectQuery query = createAttributeQuery(resource, attributeName, attributeValue); LOGGER.trace("Determining uniqueness of attribute {} using query:\n{}", attributeName, query.debugDumpLazily()); final Holder isUniqueHolder = new Holder<>(true); ResultHandler handler = (object, parentResult) -> { - if (shadowType.getOid() == null) { - // We have found a conflicting object + if (shadow.getOid() != null && shadow.getOid().equals(object.getOid())) { + // We have found ourselves. No conflict (yet). Just go on. + return true; + } else { + // We have found someone else. Conflict. isUniqueHolder.setValue(false); return false; - } else { - if (shadowType.getOid().equals(object.getOid())) { - // We have found ourselves. No conflict (yet). Just go on. - return true; - } else { - // We have found someone else. Conflict. - isUniqueHolder.setValue(false); - return false; - } } }; - modelObjectResolver.searchIterative(ShadowType.class, query, createReadOnlyCollection(), handler, task, result); + modelService.searchObjectsIterative(ShadowType.class, query, handler, createReadOnlyCollection(), task, result); return isUniqueHolder.getValue(); } @@ -1821,7 +1817,7 @@ private String createPrefixLinkByAuthSequence(String channel, String nameOfSeque private SecurityPolicyType resolveSecurityPolicy(PrismObject user) { return securityContextManager.runPrivileged(new Producer<>() { - private static final long serialVersionUID = 1L; + @Serial private static final long serialVersionUID = 1L; @Override public SecurityPolicyType run() { @@ -1996,6 +1992,7 @@ private List getDeltaBeans(Collection> deltas) t } @Override + @Deprecated public TaskType submitTaskFromTemplate(String templateTaskOid, List> extensionItems) throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, ExpressionEvaluationException, ObjectAlreadyExistsException, PolicyViolationException { @@ -2003,6 +2000,7 @@ public TaskType submitTaskFromTemplate(String templateTaskOid, List> } @Override + @Deprecated public TaskType submitTaskFromTemplate(String templateTaskOid, Map extensionValues) throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, ExpressionEvaluationException, ObjectAlreadyExistsException, PolicyViolationException { @@ -2394,6 +2392,7 @@ public T createLinkedSource(String linkType) th @Experimental @NotNull private T getFocusObjectAny() { + //noinspection unchecked LensContext lensContext = (LensContext) getModelContext(); if (lensContext == null) { throw new IllegalStateException("No model context present. Are you calling this method within model operation?"); @@ -2477,12 +2476,10 @@ private String describeResourceObjectSet(ResourceObjectSetType set, boolean long } ObjectType object = resolveReferenceInternal(ref, true); - if (!(object instanceof ResourceType)) { + if (!(object instanceof ResourceType resource)) { return null; } - ResourceType resource = (ResourceType) object; - StringBuilder sb = new StringBuilder(); sb.append(resource.getName().getOrig());