diff --git a/scim-core/src/test/java/org/apache/directory/scim/core/repository/PatchHandlerTest.java b/scim-core/src/test/java/org/apache/directory/scim/core/repository/PatchHandlerTest.java index ac9e384a..a77ba00e 100644 --- a/scim-core/src/test/java/org/apache/directory/scim/core/repository/PatchHandlerTest.java +++ b/scim-core/src/test/java/org/apache/directory/scim/core/repository/PatchHandlerTest.java @@ -250,6 +250,48 @@ public void applyRemoveItemWithFilter() { assertThat(updatedUser.getAddresses().get(0).getPostalCode()).isEqualTo("43210"); } + @Test + public void applyPrimaryString() { + ScimUser user = user().setAddresses(List.of( + new Address() + .setType("work") + .setStreetAddress("101 Main Street") + .setRegion("Springfield") + .setPostalCode("01234") + .setPrimary(true), + new Address() + .setType("home") + .setStreetAddress("202 Maple Street") + .setRegion("Otherton") + .setPostalCode("43210") + .setPrimary(false) + )); + + PatchOperation op = patchOperation(REPLACE, "addresses[primary EQ true].postalCode", "32140"); + ScimUser updatedUser = patchHandler.apply(user, List.of(op)); + assertThat(updatedUser.getAddresses().size()).isEqualTo(2); + assertThat(updatedUser.getAddresses().get(0).getPostalCode()).isEqualTo("32140"); + assertThat(updatedUser.getAddresses().get(1).getPostalCode()).isEqualTo("43210"); + + op = patchOperation(REPLACE, "addresses[primary EQ \"True\"].postalCode", "42"); + updatedUser = patchHandler.apply(user, List.of(op)); + assertThat(updatedUser.getAddresses().size()).isEqualTo(2); + assertThat(updatedUser.getAddresses().get(0).getPostalCode()).isEqualTo("42"); + assertThat(updatedUser.getAddresses().get(1).getPostalCode()).isEqualTo("43210"); + + op = patchOperation(REPLACE, "addresses[primary EQ false].postalCode", "1337"); + updatedUser = patchHandler.apply(user, List.of(op)); + assertThat(updatedUser.getAddresses().size()).isEqualTo(2); + assertThat(updatedUser.getAddresses().get(0).getPostalCode()).isEqualTo("01234"); + assertThat(updatedUser.getAddresses().get(1).getPostalCode()).isEqualTo("1337"); + + op = patchOperation(REPLACE, "addresses[primary EQ \"False\"].postalCode", "7331"); + updatedUser = patchHandler.apply(user, List.of(op)); + assertThat(updatedUser.getAddresses().size()).isEqualTo(2); + assertThat(updatedUser.getAddresses().get(0).getPostalCode()).isEqualTo("01234"); + assertThat(updatedUser.getAddresses().get(1).getPostalCode()).isEqualTo("7331"); + } + @Test public void applyRemoveAttributeWithFilter() { Address workAddress = new Address() diff --git a/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/filter/InMemoryScimFilterMatcher.java b/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/filter/InMemoryScimFilterMatcher.java index 049aec70..471d2b79 100644 --- a/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/filter/InMemoryScimFilterMatcher.java +++ b/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/filter/InMemoryScimFilterMatcher.java @@ -28,6 +28,7 @@ import java.util.Collection; import java.util.Comparator; +import java.util.Locale; import java.util.function.Predicate; class InMemoryScimFilterMatcher extends BaseFilterExpressionMapper> { @@ -181,17 +182,10 @@ protected boolean test(Schema.Attribute attribute, Object actualValue) { Object compareValue = expression.getCompareValue(); if (op == CompareOperator.EQ) { - - if (isStringExpression(attribute, compareValue) && !attribute.isCaseExact()) { - return actualValue.toString().equalsIgnoreCase(compareValue.toString()); - } - return compareValue.equals(actualValue); + return eq(attribute, actualValue, compareValue); } if (op == CompareOperator.NE) { - if (isStringExpression(attribute, compareValue) && !attribute.isCaseExact()) { - return !actualValue.toString().equalsIgnoreCase(compareValue.toString()); - } - return !compareValue.equals(actualValue); + return !eq(attribute, actualValue, compareValue); } if (op == CompareOperator.SW) { return isStringExpression(attribute, compareValue) @@ -213,6 +207,30 @@ protected boolean test(Schema.Attribute attribute, Object actualValue) { throw new ScimResourceInvalidException("Unsupported operation in filter: " + op.name()); } + + private boolean eq(Schema.Attribute attribute, Object actualValue, Object compareValue) + { + if (isBooleanStringComparison(attribute, compareValue) || (isStringExpression(attribute, compareValue) && !attribute.isCaseExact())) { + return actualValue.toString().equalsIgnoreCase(compareValue.toString()); + } + return compareValue.equals(actualValue); + } + + private boolean isBooleanStringComparison(Schema.Attribute attribute, Object compareValue) + { + // Microsoft's SCIM Validator at https://scimvalidator.microsoft.com/ has patch operations + // with expressions like [primary EQ "True"]... + if (!attribute.getType().equals(Schema.Attribute.Type.BOOLEAN)) { + return false; + } + + if (compareValue instanceof String compareValueString) { + String lowerCaseCompareValueString = compareValueString.toLowerCase(Locale.ROOT); + return "true".equals(lowerCaseCompareValueString) || "false".equals(lowerCaseCompareValueString); + } + + return false; + } } private static class CompareOperatorPredicate implements Predicate {