Check only for the existence of the attribute if only the key is specified

Closes #45983

Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
This commit is contained in:
Stefan Guilhen 2026-02-03 11:54:26 -03:00 committed by Pedro Igor
parent 021d544000
commit 2111dcf913
2 changed files with 42 additions and 13 deletions

View file

@ -50,8 +50,17 @@ public class UserAttributeWorkflowConditionProvider implements WorkflowCondition
} }
String[] parsedKeyValuePair = parseKeyValuePair(expectedAttribute); String[] parsedKeyValuePair = parseKeyValuePair(expectedAttribute);
List<String> values = user.getAttributes().getOrDefault(parsedKeyValuePair[0], List.of()); String key = parsedKeyValuePair[0];
List<String> expectedValues = List.of(parsedKeyValuePair[1].split(",")); String valuePart = parsedKeyValuePair[1];
// Presence-only: "key:" -> true if user has at least one attribute with that key
if (valuePart.isEmpty()) {
List<String> values = user.getAttributes().getOrDefault(key, List.of());
return !values.isEmpty();
}
List<String> values = user.getAttributes().getOrDefault(key, List.of());
List<String> expectedValues = List.of(valuePart.split(","));
return collectionEquals(expectedValues, values); return collectionEquals(expectedValues, values);
} }
@ -62,7 +71,14 @@ public class UserAttributeWorkflowConditionProvider implements WorkflowCondition
String[] parsedKeyValuePair = parseKeyValuePair(expectedAttribute); String[] parsedKeyValuePair = parseKeyValuePair(expectedAttribute);
String attributeName = parsedKeyValuePair[0]; String attributeName = parsedKeyValuePair[0];
List<String> expectedValues = Arrays.asList(parsedKeyValuePair[1].split(",")); String valuePart = parsedKeyValuePair[1];
// Presence-only: require at least one attribute with this name for the user
if (valuePart.isEmpty()) {
return cb.greaterThan(createTotalCountSubquery(cb, query, path, attributeName), 0L);
}
List<String> expectedValues = Arrays.asList(valuePart.split(","));
// Subquery to count how many of the expected values the user has // Subquery to count how many of the expected values the user has
// to check if there is no missing value // to check if there is no missing value
@ -95,24 +111,29 @@ public class UserAttributeWorkflowConditionProvider implements WorkflowCondition
// Subquery to count total attributes with this name for the user // Subquery to count total attributes with this name for the user
// to check if there are no extra values // to check if there are no extra values
Subquery<Long> totalCountSubquery = query.subquery(Long.class); createTotalCountSubquery(cb, query, path, attributeName);
Root<UserAttributeEntity> attrRoot2 = totalCountSubquery.from(UserAttributeEntity.class);
totalCountSubquery.select(cb.count(attrRoot2));
totalCountSubquery.where(
cb.and(
cb.equal(attrRoot2.get("user").get("id"), path.get("id")),
cb.equal(attrRoot2.get("name"), attributeName)
)
);
// Both counts must equal the expected count (exact match) // Both counts must equal the expected count (exact match)
int expectedCount = expectedValues.size(); int expectedCount = expectedValues.size();
return cb.and( return cb.and(
cb.equal(matchingCountSubquery, expectedCount), cb.equal(matchingCountSubquery, expectedCount),
cb.equal(totalCountSubquery, expectedCount) cb.equal(createTotalCountSubquery(cb, query, path, attributeName), expectedCount)
); );
} }
private Subquery<Long> createTotalCountSubquery(CriteriaBuilder cb, CriteriaQuery<String> query, Root<?> path, String attributeName) {
Subquery<Long> totalCountSubquery = query.subquery(Long.class);
Root<UserAttributeEntity> attrRoot = totalCountSubquery.from(UserAttributeEntity.class);
totalCountSubquery.select(cb.count(attrRoot));
totalCountSubquery.where(
cb.and(
cb.equal(attrRoot.get("user").get("id"), path.get("id")),
cb.equal(attrRoot.get("name"), attributeName)
)
);
return totalCountSubquery;
}
@Override @Override
public void validate() { public void validate() {
if (expectedAttribute == null) { if (expectedAttribute == null) {

View file

@ -51,6 +51,14 @@ public class UserAttributeWorkflowConditionTest extends AbstractWorkflowTest {
managedRealm.admin().users().userProfile().update(upConfig); managedRealm.admin().users().userProfile().update(upConfig);
} }
@Test
public void testConditionForAnyValuedAttribute() {
createWorkflow(List.of());
assertUserAttribute("user-1", true, "singleValue");
assertUserAttribute("user-2", true, "v1", "v2", "v3");
assertUserAttribute("user-3", false);
}
@Test @Test
public void testConditionForSingleValuedAttribute() { public void testConditionForSingleValuedAttribute() {
String expected = "valid"; String expected = "valid";