Merge pull request #551 from apache/dependabot/maven/version.spring-boot-3.2.4

Bump version.spring-boot from 3.2.3 to 3.2.4
diff --git a/pom.xml b/pom.xml
index 75b6d08..39964bb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -249,7 +249,7 @@
       <dependency>
         <groupId>ch.qos.logback</groupId>
         <artifactId>logback-classic</artifactId>
-        <version>1.4.8</version>
+        <version>1.4.12</version>
       </dependency>
       <dependency>
         <groupId>org.slf4j</groupId>
@@ -616,7 +616,7 @@
           <plugin>
             <groupId>org.jacoco</groupId>
             <artifactId>jacoco-maven-plugin</artifactId>
-            <version>0.8.11</version>
+            <version>0.8.12</version>
           </plugin>
           <plugin>
             <groupId>org.springframework.boot</groupId>
@@ -796,7 +796,7 @@
           <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-gpg-plugin</artifactId>
-            <version>3.2.1</version>
+            <version>3.2.3</version>
             <executions>
               <execution>
                 <id>sign-artifacts</id>
diff --git a/scim-core/src/main/java/org/apache/directory/scim/core/repository/ETag.java b/scim-core/src/main/java/org/apache/directory/scim/core/repository/ETag.java
new file mode 100644
index 0000000..1410060
--- /dev/null
+++ b/scim-core/src/main/java/org/apache/directory/scim/core/repository/ETag.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.directory.scim.core.repository;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Bean representing an ETag, as defined by RFC 7232 section 2.3.
+ * <p>
+ * From RFC 7644 - SCIM Protocol
+ * <p>
+ * When supported by a SCIM Server, SCIM ETags MUST be specified
+ * as an HTTP header and SHOULD be specified within the 'version'
+ * attribute contained in the resource's 'meta' attribute.
+ * <p>
+ * From RFC 7232 - HTTP Conditional Requests
+ * <p>
+ * The "ETag" header field in a response provides the current entity-tag
+ * for the selected representation, as determined at the conclusion of
+ * handling the request.  An entity-tag is an opaque validator for
+ * differentiating between multiple representations of the same
+ * resource, regardless of whether those multiple representations are
+ * due to resource state changes over time, content negotiation
+ * resulting in multiple representations being valid at the same time,
+ * or both.  An entity-tag consists of an opaque quoted string, possibly
+ * prefixed by a weakness indicator ({@code W/}).
+ * <p>
+ * Examples:<ul>
+ *      <li>ETag: "xyzzy"</li>
+ *      <li>ETag: W/"xyzzy"</li>
+ *      <li>ETag: ""</li>
+ * </ul>
+ * @see <a href="https://datatracker.ietf.org/doc/html/rfc7232#section-2.3">Conditional Requests - RFC 7232</a>
+ * @see <a href="https://datatracker.ietf.org/doc/html/rfc7644#section-3.14">SCIM Protocol -  RFC 7644</a>
+ */
+@Data
+@EqualsAndHashCode
+@RequiredArgsConstructor
+public class ETag {
+  private final String value;
+  private final boolean weak;
+}
diff --git a/scim-core/src/main/java/org/apache/directory/scim/core/repository/Repository.java b/scim-core/src/main/java/org/apache/directory/scim/core/repository/Repository.java
index 3cbbc42..d398bb4 100644
--- a/scim-core/src/main/java/org/apache/directory/scim/core/repository/Repository.java
+++ b/scim-core/src/main/java/org/apache/directory/scim/core/repository/Repository.java
@@ -19,6 +19,7 @@
 
 package org.apache.directory.scim.core.repository;
 
+import jakarta.annotation.Nullable;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
@@ -69,14 +70,14 @@
    *
    *
    * @param id the identifier of the ScimResource to update and persist.
-   * @param version an optional version (usually used as an ETag) that can be used to optimize update requests, may be compared against, the current {@code ScimResource.meta.version}.
+   * @param etags optional ETag(s) in 'If-Match' header. If not null, to avoid dirty writing, {@code ScimResource.meta.version} must match one of this set (the set should contain only one element).
    * @param resource an updated resource to persist
    * @param includedAttributes optional set of attributes to include from ScimResource, may be used to optimize queries.
    * @param excludedAttributes optional set of attributes to exclude from ScimResource, may be used to optimize queries.
    * @return The newly updated ScimResource.
    * @throws ResourceException When the ScimResource cannot be updated.
    */
-  T update(String id, String version, T resource, Set<AttributeReference> includedAttributes, Set<AttributeReference> excludedAttributes) throws ResourceException;
+  T update(String id, @Nullable Set<ETag> etags, T resource, Set<AttributeReference> includedAttributes, Set<AttributeReference> excludedAttributes) throws ResourceException;
 
   /**
    * Allows the SCIM server's REST implementation to update and existing
@@ -86,14 +87,14 @@
    * it can be used as a mechanism for caching and to ensure clients do not inadvertently overwrite other changes.
    *
    * @param id the identifier of the ScimResource to update and persist.
-   * @param version an optional version (usually used as an ETag) that can be used to optimize update requests, may be compared against, the current {@code ScimResource.meta.version}.
+   * @param etags optional ETag(s) in 'If-Match' header. If not null, to avoid dirty writing, {@code ScimResource.meta.version} must match one of this set (the set should contain only one element).
    * @param patchOperations a list of patch operations to apply to an existing resource.
    * @param includedAttributes optional set of attributes to include from ScimResource, may be used to optimize queries.
    * @param excludedAttributes optional set of attributes to exclude from ScimResource, may be used to optimize queries.
    * @return The newly updated ScimResource.
    * @throws ResourceException When the ScimResource cannot be updated.
    */
-  T patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributes, Set<AttributeReference> excludedAttributes) throws ResourceException;
+  T patch(String id, @Nullable Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributes, Set<AttributeReference> excludedAttributes) throws ResourceException;
 
   /**
    * Retrieves the ScimResource associated with the provided identifier.
diff --git a/scim-server-examples/scim-server-jersey/src/main/java/org/apache/directory/scim/example/jersey/service/InMemoryGroupService.java b/scim-server-examples/scim-server-jersey/src/main/java/org/apache/directory/scim/example/jersey/service/InMemoryGroupService.java
index 42b09e3..6d248ab 100644
--- a/scim-server-examples/scim-server-jersey/src/main/java/org/apache/directory/scim/example/jersey/service/InMemoryGroupService.java
+++ b/scim-server-examples/scim-server-jersey/src/main/java/org/apache/directory/scim/example/jersey/service/InMemoryGroupService.java
@@ -23,6 +23,7 @@
 import jakarta.inject.Inject;
 import jakarta.ws.rs.core.Response;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.core.repository.PatchHandler;
 import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
 import org.apache.directory.scim.core.repository.Repository;
@@ -104,13 +105,13 @@
   }
 
   @Override
-  public ScimGroup update(String id, String version, ScimGroup resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimGroup update(String id, Set<ETag> etags, ScimGroup resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     groups.put(id, resource);
     return resource;
   }
 
   @Override
-  public ScimGroup patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimGroup patch(String id, Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     ScimGroup resource = patchHandler.apply(get(id), patchOperations);
     groups.put(id, resource);
     return resource;
diff --git a/scim-server-examples/scim-server-jersey/src/main/java/org/apache/directory/scim/example/jersey/service/InMemoryUserService.java b/scim-server-examples/scim-server-jersey/src/main/java/org/apache/directory/scim/example/jersey/service/InMemoryUserService.java
index 2f00013..cbbe1b0 100644
--- a/scim-server-examples/scim-server-jersey/src/main/java/org/apache/directory/scim/example/jersey/service/InMemoryUserService.java
+++ b/scim-server-examples/scim-server-jersey/src/main/java/org/apache/directory/scim/example/jersey/service/InMemoryUserService.java
@@ -32,6 +32,7 @@
 import jakarta.inject.Named;
 
 import jakarta.ws.rs.core.Response;
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.core.repository.PatchHandler;
 import org.apache.directory.scim.example.jersey.extensions.LuckyNumberExtension;
 import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
@@ -137,13 +138,13 @@
   }
 
   @Override
-  public ScimUser update(String id, String version, ScimUser resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimUser update(String id, Set<ETag> etags, ScimUser resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     users.put(id, resource);
     return resource;
   }
 
   @Override
-  public ScimUser patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimUser patch(String id, Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     ScimUser resource = patchHandler.apply(get(id), patchOperations);
     users.put(id, resource);
     return resource;
diff --git a/scim-server-examples/scim-server-memory/src/main/java/org/apache/directory/scim/example/memory/service/InMemoryGroupService.java b/scim-server-examples/scim-server-memory/src/main/java/org/apache/directory/scim/example/memory/service/InMemoryGroupService.java
index f5de84a..2d9ad1e 100644
--- a/scim-server-examples/scim-server-memory/src/main/java/org/apache/directory/scim/example/memory/service/InMemoryGroupService.java
+++ b/scim-server-examples/scim-server-memory/src/main/java/org/apache/directory/scim/example/memory/service/InMemoryGroupService.java
@@ -23,6 +23,7 @@
 import jakarta.inject.Inject;
 import jakarta.ws.rs.core.Response;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.core.repository.PatchHandler;
 import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
 import org.apache.directory.scim.core.repository.Repository;
@@ -104,13 +105,13 @@
   }
 
   @Override
-  public ScimGroup update(String id, String version, ScimGroup resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimGroup update(String id, Set<ETag> etags, ScimGroup resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     groups.put(id, resource);
     return resource;
   }
 
   @Override
-  public ScimGroup patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimGroup patch(String id, Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     ScimGroup resource = patchHandler.apply(get(id), patchOperations);
     groups.put(id, resource);
     return resource;
diff --git a/scim-server-examples/scim-server-memory/src/main/java/org/apache/directory/scim/example/memory/service/InMemoryUserService.java b/scim-server-examples/scim-server-memory/src/main/java/org/apache/directory/scim/example/memory/service/InMemoryUserService.java
index 562cc66..f465f0a 100644
--- a/scim-server-examples/scim-server-memory/src/main/java/org/apache/directory/scim/example/memory/service/InMemoryUserService.java
+++ b/scim-server-examples/scim-server-memory/src/main/java/org/apache/directory/scim/example/memory/service/InMemoryUserService.java
@@ -32,6 +32,7 @@
 import jakarta.inject.Named;
 
 import jakarta.ws.rs.core.Response;
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.core.repository.PatchHandler;
 import org.apache.directory.scim.example.memory.extensions.LuckyNumberExtension;
 import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
@@ -137,13 +138,13 @@
   }
 
   @Override
-  public ScimUser update(String id, String version, ScimUser resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimUser update(String id, Set<ETag> etags, ScimUser resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     users.put(id, resource);
     return resource;
   }
 
   @Override
-  public ScimUser patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimUser patch(String id, Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     ScimUser resource = patchHandler.apply(get(id), patchOperations);
     users.put(id, resource);
     return resource;
diff --git a/scim-server-examples/scim-server-quarkus/pom.xml b/scim-server-examples/scim-server-quarkus/pom.xml
index 1113750..df40aeb 100644
--- a/scim-server-examples/scim-server-quarkus/pom.xml
+++ b/scim-server-examples/scim-server-quarkus/pom.xml
@@ -29,7 +29,7 @@
 
   <properties>
     <module.name>org.apache.directory.scim.example.quarkus</module.name>
-    <version.quarkus>3.8.2</version.quarkus>
+    <version.quarkus>3.9.1</version.quarkus>
     <max.jdk.version>17</max.jdk.version>
     <!-- disable discovery of tests in other jars, tests are wrapped directly in this project to run with Quarkus -->
     <dependenciesToScan />
diff --git a/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryGroupService.java b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryGroupService.java
index af28ae7..f17bde1 100644
--- a/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryGroupService.java
+++ b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryGroupService.java
@@ -23,6 +23,7 @@
 import jakarta.inject.Inject;
 import jakarta.ws.rs.core.Response;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.core.repository.PatchHandler;
 import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
 import org.apache.directory.scim.core.repository.Repository;
@@ -104,13 +105,13 @@
   }
 
   @Override
-  public ScimGroup update(String id, String version, ScimGroup resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimGroup update(String id, Set<ETag> etags, ScimGroup resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     groups.put(id, resource);
     return resource;
   }
 
   @Override
-  public ScimGroup patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimGroup patch(String id, Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     ScimGroup resource = patchHandler.apply(get(id), patchOperations);
     groups.put(id, resource);
     return resource;
diff --git a/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryUserService.java b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryUserService.java
index b849846..8aa6784 100644
--- a/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryUserService.java
+++ b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryUserService.java
@@ -28,6 +28,7 @@
 import jakarta.inject.Named;
 
 import jakarta.ws.rs.core.Response;
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.core.repository.PatchHandler;
 import org.apache.directory.scim.example.quarkus.extensions.LuckyNumberExtension;
 import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
@@ -133,13 +134,13 @@
   }
 
   @Override
-  public ScimUser update(String id, String version, ScimUser resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimUser update(String id, Set<ETag> etags, ScimUser resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     users.put(id, resource);
     return resource;
   }
 
   @Override
-  public ScimUser patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimUser patch(String id, Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     ScimUser resource = patchHandler.apply(get(id), patchOperations);
     users.put(id, resource);
     return resource;
diff --git a/scim-server-examples/scim-server-spring-boot/src/main/java/org/apache/directory/scim/example/spring/service/InMemoryGroupService.java b/scim-server-examples/scim-server-spring-boot/src/main/java/org/apache/directory/scim/example/spring/service/InMemoryGroupService.java
index 0df2da7..df4b827 100644
--- a/scim-server-examples/scim-server-spring-boot/src/main/java/org/apache/directory/scim/example/spring/service/InMemoryGroupService.java
+++ b/scim-server-examples/scim-server-spring-boot/src/main/java/org/apache/directory/scim/example/spring/service/InMemoryGroupService.java
@@ -21,6 +21,7 @@
 
 import jakarta.annotation.PostConstruct;
 import jakarta.ws.rs.core.Response;
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.core.repository.PatchHandler;
 import org.apache.directory.scim.core.repository.Repository;
 import org.apache.directory.scim.core.schema.SchemaRegistry;
@@ -94,13 +95,13 @@
   }
 
   @Override
-  public ScimGroup update(String id, String version, ScimGroup resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimGroup update(String id, Set<ETag> etags, ScimGroup resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     groups.put(id, resource);
     return resource;
   }
 
   @Override
-  public ScimGroup patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimGroup patch(String id, Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     ScimGroup resource = patchHandler.apply(get(id), patchOperations);
     groups.put(id, resource);
     return resource;
diff --git a/scim-server-examples/scim-server-spring-boot/src/main/java/org/apache/directory/scim/example/spring/service/InMemoryUserService.java b/scim-server-examples/scim-server-spring-boot/src/main/java/org/apache/directory/scim/example/spring/service/InMemoryUserService.java
index 36ba0cc..39c2eef 100644
--- a/scim-server-examples/scim-server-spring-boot/src/main/java/org/apache/directory/scim/example/spring/service/InMemoryUserService.java
+++ b/scim-server-examples/scim-server-spring-boot/src/main/java/org/apache/directory/scim/example/spring/service/InMemoryUserService.java
@@ -29,6 +29,7 @@
 import jakarta.annotation.PostConstruct;
 
 import jakarta.ws.rs.core.Response;
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.core.repository.PatchHandler;
 import org.apache.directory.scim.core.repository.Repository;
 import org.apache.directory.scim.core.schema.SchemaRegistry;
@@ -127,13 +128,13 @@
   }
 
   @Override
-  public ScimUser update(String id, String version, ScimUser resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimUser update(String id, Set<ETag> etags, ScimUser resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     users.put(id, resource);
     return resource;
   }
 
   @Override
-  public ScimUser patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimUser patch(String id, Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     ScimUser resource = patchHandler.apply(get(id), patchOperations);
     users.put(id, resource);
     return resource;
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/BaseResourceTypeResourceImpl.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/BaseResourceTypeResourceImpl.java
index b378c1b..f8a1fc6 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/rest/BaseResourceTypeResourceImpl.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/BaseResourceTypeResourceImpl.java
@@ -33,6 +33,7 @@
 import jakarta.ws.rs.core.Response.Status;
 import jakarta.ws.rs.core.Response.Status.Family;
 
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.protocol.exception.ScimException;
 import org.apache.directory.scim.server.exception.*;
 import org.apache.directory.scim.core.repository.RepositoryRegistry;
@@ -70,7 +71,7 @@
 
   private final RepositoryRegistry repositoryRegistry;
 
-  private final  AttributeUtil attributeUtil;
+  private final AttributeUtil attributeUtil;
 
   private final Class<T> resourceClass;
 
@@ -254,14 +255,14 @@
 
   @Override
   public Response update(T resource, String id, AttributeReferenceListWrapper attributes, AttributeReferenceListWrapper excludedAttributes) throws ScimException, ResourceException {
-    return update(attributes, excludedAttributes, (etag, includeAttributes, excludeAttributes, repository)
-      -> repository.update(id, etag,resource, includeAttributes, excludeAttributes));
+    return update(attributes, excludedAttributes, (etags, includeAttributes, excludeAttributes, repository)
+      -> repository.update(id, etags, resource, includeAttributes, excludeAttributes));
   }
 
   @Override
   public Response patch(PatchRequest patchRequest, String id, AttributeReferenceListWrapper attributes, AttributeReferenceListWrapper excludedAttributes) throws ScimException, ResourceException {
-    return update(attributes, excludedAttributes, (etag, includeAttributes, excludeAttributes, repository)
-      -> repository.patch(id, etag, patchRequest.getPatchOperationList(), includeAttributes, excludeAttributes));
+    return update(attributes, excludedAttributes, (etags, includeAttributes, excludeAttributes, repository)
+      -> repository.patch(id, etags, patchRequest.getPatchOperationList(), includeAttributes, excludeAttributes));
   }
 
   @Override
@@ -279,8 +280,10 @@
     Set<AttributeReference> excludedAttributeReferences = AttributeReferenceListWrapper.getAttributeReferences(excludedAttributes);
     validateAttributes(attributeReferences, excludedAttributeReferences);
 
-    String requestEtag = headers.getHeaderString("ETag");
-    T updated = updateFunction.update(requestEtag, attributeReferences, excludedAttributeReferences, repository);
+    String requestEtag = headers.getHeaderString("If-Match");
+    Set<ETag> etags = EtagParser.parseETag(requestEtag);
+
+    T updated = updateFunction.update(etags, attributeReferences, excludedAttributeReferences, repository);
 
     // Process Attributes
     updated = processFilterAttributeExtensions(repository, updated, attributeReferences, excludedAttributeReferences);
@@ -371,6 +374,6 @@
 
   @FunctionalInterface
   private interface UpdateFunction<T extends ScimResource> {
-    T update(String etag, Set<AttributeReference> includeAttributes, Set<AttributeReference> excludeAttributes, Repository<T> repository) throws ResourceException;
+    T update(Set<ETag> etags, Set<AttributeReference> includeAttributes, Set<AttributeReference> excludeAttributes, Repository<T> repository) throws ResourceException;
   }
 }
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/EtagParser.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/EtagParser.java
new file mode 100644
index 0000000..ffe6711
--- /dev/null
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/EtagParser.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.directory.scim.server.rest;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.directory.scim.core.repository.ETag;
+
+public final class EtagParser {
+
+  private EtagParser() {
+  }
+
+  /**
+   * Parse comma-separated entity tags
+   *
+   * @param value
+   * @return
+   * @throws IllegalArgumentException
+   */
+  public static Set<ETag> parseETag(String value) throws IllegalArgumentException {
+    if (StringUtils.isNotBlank(value)) {
+      Set<ETag> result = new HashSet<>();
+
+      for (String etag : value.split(",")) {
+        etag = etag.trim();
+        boolean weakTag = false;
+
+        if (etag.startsWith("W/")) {
+          weakTag = true;
+          etag = etag.substring(2);
+        }
+
+        if (etag.startsWith("\"")) {
+          etag = etag.substring(1);
+        }
+
+        if (etag.endsWith("\"")) {
+          etag = etag.substring(0, etag.length() - 1);
+        }
+
+        result.add(new ETag(etag, weakTag));
+      }
+      return result;
+    } else {
+      return null;
+    }
+  }
+}
diff --git a/scim-server/src/test/java/org/apache/directory/scim/server/it/testapp/InMemoryGroupService.java b/scim-server/src/test/java/org/apache/directory/scim/server/it/testapp/InMemoryGroupService.java
index 2dac3ea..9af8eeb 100644
--- a/scim-server/src/test/java/org/apache/directory/scim/server/it/testapp/InMemoryGroupService.java
+++ b/scim-server/src/test/java/org/apache/directory/scim/server/it/testapp/InMemoryGroupService.java
@@ -25,6 +25,7 @@
 import jakarta.inject.Named;
 import jakarta.ws.rs.core.Response;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.core.repository.PatchHandler;
 import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
 import org.apache.directory.scim.core.repository.Repository;
@@ -98,13 +99,13 @@
   }
 
   @Override
-  public ScimGroup update(String id, String version, ScimGroup resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimGroup update(String id, Set<ETag> etags, ScimGroup resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     groups.put(id, resource);
     return resource;
   }
 
   @Override
-  public ScimGroup patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimGroup patch(String id, Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     ScimGroup resource = patchHandler.apply(get(id), patchOperations);
     groups.put(id, resource);
     return resource;
diff --git a/scim-server/src/test/java/org/apache/directory/scim/server/it/testapp/InMemoryUserService.java b/scim-server/src/test/java/org/apache/directory/scim/server/it/testapp/InMemoryUserService.java
index 909df75..a870610 100644
--- a/scim-server/src/test/java/org/apache/directory/scim/server/it/testapp/InMemoryUserService.java
+++ b/scim-server/src/test/java/org/apache/directory/scim/server/it/testapp/InMemoryUserService.java
@@ -24,6 +24,7 @@
 import jakarta.inject.Inject;
 import jakarta.inject.Named;
 import jakarta.ws.rs.core.Response;
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.core.repository.PatchHandler;
 import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
 import org.apache.directory.scim.core.repository.Repository;
@@ -130,13 +131,13 @@
   }
 
   @Override
-  public ScimUser update(String id, String version, ScimUser resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimUser update(String id, Set<ETag> etags, ScimUser resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     users.put(id, resource);
     return resource;
   }
 
   @Override
-  public ScimUser patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimUser patch(String id, Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     ScimUser resource = patchHandler.apply(get(id), patchOperations);
     users.put(id, resource);
     return resource;
diff --git a/scim-server/src/test/java/org/apache/directory/scim/server/rest/EtagParserTest.java b/scim-server/src/test/java/org/apache/directory/scim/server/rest/EtagParserTest.java
new file mode 100644
index 0000000..6ca513f
--- /dev/null
+++ b/scim-server/src/test/java/org/apache/directory/scim/server/rest/EtagParserTest.java
@@ -0,0 +1,68 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you 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 org.apache.directory.scim.server.rest;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Set;
+import org.apache.directory.scim.core.repository.ETag;
+import org.junit.jupiter.api.Test;
+
+public class EtagParserTest {
+
+  @Test
+  public void testParse() {
+    Set<ETag> etags = EtagParser.parseETag("\"67ab43\", \"54ed21\", W/\"7892dd\"");
+
+    assertThat(etags)
+      .isNotNull()
+      .hasSize(3)
+      .containsOnly(
+        new ETag("67ab43", false),
+        new ETag("54ed21", false),
+        new ETag("7892dd", true));
+  }
+
+  @Test
+  public void testParseWildcard() {
+    Set<ETag> etags = EtagParser.parseETag("*");
+
+    assertThat(etags)
+      .isNotNull()
+      .hasSize(1)
+      .containsOnly(
+        new ETag("*", false));
+  }
+
+  @Test
+  public void testParseEmpty() {
+    Set<ETag> etags = EtagParser.parseETag("");
+    assertThat(etags).isNull();
+  }
+
+  @Test
+  public void testParseNull() {
+    assertThat(EtagParser.parseETag(null))
+      .isNull();
+  }
+}
diff --git a/scim-spec/scim-spec-protocol/pom.xml b/scim-spec/scim-spec-protocol/pom.xml
index 85c32dc..c07ff42 100644
--- a/scim-spec/scim-spec-protocol/pom.xml
+++ b/scim-spec/scim-spec-protocol/pom.xml
@@ -41,7 +41,7 @@
 		<dependency>
 			<groupId>io.swagger.core.v3</groupId>
 			<artifactId>swagger-annotations</artifactId>
-			<version>2.2.20</version>
+			<version>2.2.21</version>
 		</dependency>
 		<dependency>
 			<groupId>org.apache.directory.scimple</groupId>
diff --git a/support/spring-boot/src/test/java/org/apache/directory/scim/spring/it/app/InMemoryGroupService.java b/support/spring-boot/src/test/java/org/apache/directory/scim/spring/it/app/InMemoryGroupService.java
index 07a79d0..d849b72 100644
--- a/support/spring-boot/src/test/java/org/apache/directory/scim/spring/it/app/InMemoryGroupService.java
+++ b/support/spring-boot/src/test/java/org/apache/directory/scim/spring/it/app/InMemoryGroupService.java
@@ -22,6 +22,7 @@
 import jakarta.annotation.PostConstruct;
 import jakarta.ws.rs.core.Response;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.core.repository.PatchHandler;
 import org.apache.directory.scim.core.repository.Repository;
 import org.apache.directory.scim.core.schema.SchemaRegistry;
@@ -93,13 +94,13 @@
   }
 
   @Override
-  public ScimGroup update(String id, String version, ScimGroup resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimGroup update(String id, Set<ETag> etags, ScimGroup resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     groups.put(id, resource);
     return resource;
   }
 
   @Override
-  public ScimGroup patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimGroup patch(String id, Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     ScimGroup resource = patchHandler.apply(get(id), patchOperations);
     groups.put(id, resource);
     return resource;
diff --git a/support/spring-boot/src/test/java/org/apache/directory/scim/spring/it/app/InMemoryUserService.java b/support/spring-boot/src/test/java/org/apache/directory/scim/spring/it/app/InMemoryUserService.java
index 430d837..9ec72a8 100644
--- a/support/spring-boot/src/test/java/org/apache/directory/scim/spring/it/app/InMemoryUserService.java
+++ b/support/spring-boot/src/test/java/org/apache/directory/scim/spring/it/app/InMemoryUserService.java
@@ -21,6 +21,7 @@
 
 import jakarta.annotation.PostConstruct;
 import jakarta.ws.rs.core.Response;
+import org.apache.directory.scim.core.repository.ETag;
 import org.apache.directory.scim.core.repository.PatchHandler;
 import org.apache.directory.scim.core.repository.Repository;
 import org.apache.directory.scim.core.schema.SchemaRegistry;
@@ -124,13 +125,13 @@
   }
 
   @Override
-  public ScimUser update(String id, String version, ScimUser resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimUser update(String id, Set<ETag> etags, ScimUser resource, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     users.put(id, resource);
     return resource;
   }
 
   @Override
-  public ScimUser patch(String id, String version, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
+  public ScimUser patch(String id, Set<ETag> etags, List<PatchOperation> patchOperations, Set<AttributeReference> includedAttributeReferences, Set<AttributeReference> excludedAttributeReferences) throws ResourceException {
     ScimUser resource = patchHandler.apply(get(id), patchOperations);
     users.put(id, resource);
     return resource;