Author: stillalex
Date: Wed Jun 28 15:03:41 2017
New Revision: 1800179

URL: http://svn.apache.org/viewvc?rev=1800179&view=rev
Log:
OAK-3374 Concurrent Updates of Group's Membership Results in Conflict


Added:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/RepMembersConflictHandler.java
   (with props)
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RepMembersConflictHandlerTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/CompositeAuthorizationTest.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/package-info.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/package-info.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/package-info.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/package-info.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/package-info.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/package-info.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java

Modified: 
jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/CompositeAuthorizationTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/CompositeAuthorizationTest.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/CompositeAuthorizationTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/CompositeAuthorizationTest.java
 Wed Jun 28 15:03:41 2017
@@ -41,6 +41,7 @@ import org.apache.jackrabbit.oak.securit
 import 
org.apache.jackrabbit.oak.security.authorization.composite.CompositeAuthorizationConfiguration;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.MoveTracker;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
 import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
 import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
 import org.apache.jackrabbit.oak.spi.lifecycle.WorkspaceInitializer;
@@ -166,6 +167,12 @@ public class CompositeAuthorizationTest
             return Collections.EMPTY_LIST;
         }
 
+        @Nonnull
+        @Override
+        public List<ThreeWayConflictHandler> getConflictHandlers() {
+            return Collections.EMPTY_LIST;
+        }
+
         @Nonnull
         @Override
         public List<ProtectedItemImporter> getProtectedItemImporters() {

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java 
(original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java 
Wed Jun 28 15:03:41 2017
@@ -79,6 +79,7 @@ import org.apache.jackrabbit.oak.plugins
 import 
org.apache.jackrabbit.oak.plugins.index.property.jmx.PropertyIndexAsyncReindex;
 import 
org.apache.jackrabbit.oak.plugins.index.property.jmx.PropertyIndexAsyncReindexMBean;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.spi.commit.CompositeConflictHandler;
 import org.apache.jackrabbit.oak.spi.query.QueryEngineSettings;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
@@ -146,6 +147,8 @@ public class Oak {
 
     private List<EditorProvider> editorProviders = newArrayList();
 
+    private CompositeConflictHandler conflictHandler;
+
     private SecurityProvider securityProvider;
 
     private ScheduledExecutorService scheduledExecutor;
@@ -484,6 +487,10 @@ public class Oak {
             if (ri != RepositoryInitializer.DEFAULT) {
                 initializers.add(ri);
             }
+
+            for (ThreeWayConflictHandler tch : sc.getConflictHandlers()) {
+                with(tch);
+            }
         }
         return this;
     }
@@ -505,7 +512,18 @@ public class Oak {
     public Oak with(@Nonnull ThreeWayConflictHandler conflictHandler) {
         checkNotNull(conflictHandler);
         withEditorHook();
-        commitHooks.add(new ConflictHook(conflictHandler));
+
+        if (this.conflictHandler == null) {
+            if (conflictHandler instanceof CompositeConflictHandler) {
+                this.conflictHandler = (CompositeConflictHandler) 
conflictHandler;
+            } else {
+                this.conflictHandler = new CompositeConflictHandler();
+                this.conflictHandler.addHandler(conflictHandler);
+            }
+            commitHooks.add(new ConflictHook(conflictHandler));
+        } else {
+            this.conflictHandler.addHandler(conflictHandler);
+        }
         return this;
     }
 

Added: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/RepMembersConflictHandler.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/RepMembersConflictHandler.java?rev=1800179&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/RepMembersConflictHandler.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/RepMembersConflictHandler.java
 Wed Jun 28 15:03:41 2017
@@ -0,0 +1,162 @@
+/*
+ * 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.jackrabbit.oak.security.user;
+
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyBuilder;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import com.google.common.collect.Sets;
+
+/**
+ * The {@code RepMembersConflictHandler} takes care of merging the {@code 
rep:members} property
+ * during parallel updates.
+ *<p>
+ * The conflict handler deals with the following conflicts:
+ * <ul>
+ *     <li>{@code addExistingProperty}  : {@code Resolution.MERGED},</li>
+ *     <li>{@code changeDeletedProperty}: {@code Resolution.THEIRS}, removing 
the members property takes precedence.
+ *     <li>{@code changeChangedProperty}: {@code Resolution.MERGED}, merge of 
the 2 members sets into a single one
+ *     <li>{@code deleteChangedProperty}: {@code Resolution.OURS} removing the 
members property takes precedence.
+ * </ul>
+ */
+public class RepMembersConflictHandler implements ThreeWayConflictHandler {
+
+    @Nonnull
+    @Override
+    public Resolution addExistingProperty(@Nonnull NodeBuilder parent, 
@Nonnull PropertyState ours,
+            @Nonnull PropertyState theirs) {
+        if (isRepMembersProperty(theirs)) {
+            mergeChange(parent, ours, theirs,Sets.newHashSet());
+            return Resolution.MERGED;
+        } else {
+            return Resolution.IGNORED;
+        }
+    }
+
+    @Override
+    @Nonnull
+    public Resolution changeDeletedProperty(@Nonnull NodeBuilder parent, 
@Nonnull PropertyState ours,
+            @Nonnull PropertyState base) {
+        if (isRepMembersProperty(ours)) {
+            // removing the members property takes precedence
+            return Resolution.THEIRS;
+        } else {
+            return Resolution.IGNORED;
+        }
+    }
+
+    @Nonnull
+    @Override
+    public Resolution changeChangedProperty(@Nonnull NodeBuilder parent, 
@Nonnull PropertyState ours,
+            @Nonnull PropertyState theirs, @Nonnull PropertyState base) {
+        if (isRepMembersProperty(theirs)) {
+            Set<String> baseMembers = 
Sets.newHashSet(base.getValue(Type.STRINGS));
+            mergeChange(parent, ours, theirs, baseMembers);
+            return Resolution.MERGED;
+        } else {
+             return Resolution.IGNORED;
+        }
+    }
+
+    @Nonnull
+    @Override
+    public Resolution deleteDeletedProperty(@Nonnull NodeBuilder parent, 
@Nonnull PropertyState base) {
+        // both are removing the members property, ignoring
+        return Resolution.IGNORED;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution deleteChangedProperty(@Nonnull NodeBuilder parent, 
@Nonnull PropertyState theirs,
+            @Nonnull PropertyState base) {
+        if (isRepMembersProperty(theirs)) {
+            // removing the members property takes precedence
+            return Resolution.OURS;
+        } else {
+            return Resolution.IGNORED;
+        }
+    }
+
+
+    @Nonnull
+    @Override
+    public Resolution addExistingNode(@Nonnull NodeBuilder parent, @Nonnull 
String name, @Nonnull NodeState ours,
+            @Nonnull NodeState theirs) {
+        return Resolution.IGNORED;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution changeDeletedNode(@Nonnull NodeBuilder parent, @Nonnull 
String name, @Nonnull NodeState ours,
+            @Nonnull NodeState base) {
+        return Resolution.IGNORED;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution deleteChangedNode(@Nonnull NodeBuilder parent, @Nonnull 
String name, @Nonnull NodeState theirs,
+            @Nonnull NodeState base) {
+        return Resolution.IGNORED;
+    }
+
+    @Nonnull
+    @Override
+    public Resolution deleteDeletedNode(@Nonnull NodeBuilder parent, @Nonnull 
String name, @Nonnull NodeState base) {
+        return Resolution.IGNORED;
+    }
+
+    //----------------------------< internal 
>----------------------------------
+
+    private static void mergeChange(NodeBuilder parent, PropertyState ours, 
PropertyState theirs, Set<String> base) {
+        PropertyBuilder<String> merged = PropertyBuilder.array(Type.STRING);
+        merged.setName(UserConstants.REP_MEMBERS);
+
+        Set<String> theirMembers = 
Sets.newHashSet(theirs.getValue(Type.STRINGS));
+        Set<String> ourMembers = Sets.newHashSet(ours.getValue(Type.STRINGS));
+
+        // merge ours and theirs to a de-duplicated set
+        Set<String> combined = Sets.newHashSet(Sets.intersection(ourMembers, 
theirMembers));
+        for (String m : Sets.difference(ourMembers, theirMembers)) {
+            if (!base.contains(m)) {
+                combined.add(m);
+            }
+        }
+        for (String m : Sets.difference(theirMembers, ourMembers)) {
+            if (!base.contains(m)) {
+                combined.add(m);
+            }
+        }
+        merged.addValues(combined);
+        parent.setProperty(merged.getPropertyState());
+    }
+
+    private static boolean isRepMembersProperty(PropertyState p) {
+        return UserConstants.REP_MEMBERS.equals(p.getName());
+    }
+
+}

Propchange: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/RepMembersConflictHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
 Wed Jun 28 15:03:41 2017
@@ -37,6 +37,7 @@ import org.apache.jackrabbit.oak.api.Roo
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.security.user.autosave.AutoSaveEnabledManager;
 import org.apache.jackrabbit.oak.spi.commit.MoveTracker;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
 import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
 import org.apache.jackrabbit.oak.spi.lifecycle.WorkspaceInitializer;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationBase;
@@ -181,6 +182,12 @@ public class UserConfigurationImpl exten
     }
 
     @Nonnull
+    @Override
+    public List<ThreeWayConflictHandler> getConflictHandlers() {
+        return ImmutableList.of(new RepMembersConflictHandler());
+    }
+
+    @Nonnull
     @Override
     public List<ProtectedItemImporter> getProtectedItemImporters() {
         return Collections.<ProtectedItemImporter>singletonList(new 
UserImporter(getParameters()));

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java
 Wed Jun 28 15:03:41 2017
@@ -28,6 +28,7 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import aQute.bnd.annotation.ProviderType;
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
@@ -39,6 +40,7 @@ import org.apache.jackrabbit.oak.api.Tre
 import org.apache.jackrabbit.oak.plugins.tree.TreeLocation;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.MoveTracker;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
 import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
 import org.apache.jackrabbit.oak.spi.lifecycle.CompositeInitializer;
 import org.apache.jackrabbit.oak.spi.lifecycle.CompositeWorkspaceInitializer;
@@ -51,6 +53,7 @@ import org.osgi.framework.Constants;
  * Abstract base implementation for {@link SecurityConfiguration}s that can
  * combine different implementations.
  */
+@ProviderType
 public abstract class CompositeConfiguration<T extends SecurityConfiguration> 
implements SecurityConfiguration {
 
     /**
@@ -213,6 +216,12 @@ public abstract class CompositeConfigura
     }
 
     @Nonnull
+    @Override
+    public List<ThreeWayConflictHandler> getConflictHandlers() {
+        return 
ImmutableList.copyOf(Iterables.concat(Lists.transform(getConfigurations(), 
securityConfiguration -> securityConfiguration.getConflictHandlers())));
+    }
+
+    @Nonnull
     @Override
     public List<ProtectedItemImporter> getProtectedItemImporters() {
         return 
ImmutableList.copyOf(Iterables.concat(Lists.transform(getConfigurations(), new 
Function<T, List<? extends ProtectedItemImporter>>() {

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java
 Wed Jun 28 15:03:41 2017
@@ -23,8 +23,10 @@ import java.util.Set;
 
 import javax.annotation.Nonnull;
 
+import aQute.bnd.annotation.ProviderType;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.MoveTracker;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
 import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
 import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
 import org.apache.jackrabbit.oak.spi.lifecycle.WorkspaceInitializer;
@@ -33,6 +35,7 @@ import org.apache.jackrabbit.oak.spi.xml
 /**
  * Base interface for all security related configurations.
  */
+@ProviderType
 public interface SecurityConfiguration {
 
     /**
@@ -99,6 +102,14 @@ public interface SecurityConfiguration {
                                                     @Nonnull MoveTracker 
moveTracker);
 
     /**
+     * Returns the list of conflict handlers available for this security 
configuration.
+     *
+     * @return A list of {@link 
org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler}.
+     */
+    @Nonnull
+    List<ThreeWayConflictHandler> getConflictHandlers();
+
+    /**
      * @return The list of protected item importers defined by this 
configuration.
      */
     @Nonnull
@@ -153,6 +164,12 @@ public interface SecurityConfiguration {
             return Collections.emptyList();
         }
 
+        @Nonnull
+        @Override
+        public List<ThreeWayConflictHandler> getConflictHandlers() {
+            return Collections.emptyList();
+        }
+
         @Nonnull
         @Override
         public List<ProtectedItemImporter> getProtectedItemImporters() {

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/package-info.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/package-info.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/package-info.java
 Wed Jun 28 15:03:41 2017
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.2.0")
+@Version("1.3.0")
 package org.apache.jackrabbit.oak.spi.security.authentication;
 
 import aQute.bnd.annotation.Version;

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/package-info.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/package-info.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/package-info.java
 Wed Jun 28 15:03:41 2017
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.4.1")
+@Version("1.5.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.spi.security.authentication.token;
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/package-info.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/package-info.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/package-info.java
 Wed Jun 28 15:03:41 2017
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.0")
+@Version("1.1.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.spi.security.authorization;
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/package-info.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/package-info.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/package-info.java
 Wed Jun 28 15:03:41 2017
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("2.1.0")
+@Version("2.2.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.spi.security;
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java
 Wed Jun 28 15:03:41 2017
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.4.0")
+@Version("1.5.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.spi.security.principal;
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/package-info.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/package-info.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/package-info.java
 Wed Jun 28 15:03:41 2017
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.1.0")
+@Version("1.2.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.spi.security.privilege;
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/package-info.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/package-info.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/package-info.java
 Wed Jun 28 15:03:41 2017
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("2.2.0")
+@Version("2.3.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.spi.security.user;
 

Added: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RepMembersConflictHandlerTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RepMembersConflictHandlerTest.java?rev=1800179&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RepMembersConflictHandlerTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RepMembersConflictHandlerTest.java
 Wed Jun 28 15:03:41 2017
@@ -0,0 +1,287 @@
+/*
+ * 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.jackrabbit.oak.security.user;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.junit.Test;
+
+public class RepMembersConflictHandlerTest extends AbstractSecurityTest {
+
+    /**
+     * The id of the test group
+     */
+    private static final String GROUP_ID = "test-groupId";
+
+    private Group group;
+    private User[] users;
+
+    @Override
+    public void before() throws Exception {
+        super.before();
+        UserManager um = getUserManager(root);
+        // create a group to receive users
+        group = um.createGroup(GROUP_ID);
+        // create future members of the above group
+        User u1 = um.createUser("u1", "pass");
+        User u2 = um.createUser("u2", "pass");
+        User u3 = um.createUser("u3", "pass");
+        User u4 = um.createUser("u4", "pass");
+        User u5 = um.createUser("u5", "pass");
+        root.commit();
+        users = new User[] { u1, u2, u3, u4, u5 };
+    }
+
+    @Test
+    public void addExistingProperty() throws Exception {
+        Root ours = login(getAdminCredentials()).getLatestRoot();
+        Root theirs = login(getAdminCredentials()).getLatestRoot();
+
+        add(ours, users[1].getID());
+        add(theirs, users[2].getID());
+
+        root.refresh();
+        assertTrue(group.isDeclaredMember(users[1]));
+        assertTrue(group.isDeclaredMember(users[2]));
+    }
+
+    /**
+     * Add-Add test
+     */
+    @Test
+    public void changeChangedPropertyAA() throws Exception {
+        add(root, users[0].getID());
+
+        Root ours = login(getAdminCredentials()).getLatestRoot();
+        Root theirs = login(getAdminCredentials()).getLatestRoot();
+
+        add(ours, users[1].getID());
+        add(theirs, users[2].getID());
+
+        root.refresh();
+        assertTrue(group.isDeclaredMember(users[0]));
+        assertTrue(group.isDeclaredMember(users[1]));
+        assertTrue(group.isDeclaredMember(users[2]));
+    }
+
+    /**
+     * Remove-Remove test
+     */
+    @Test
+    public void changeChangedPropertyRR() throws Exception {
+        add(root, users[0].getID(), users[1].getID(), users[2].getID());
+
+        Root ours = login(getAdminCredentials()).getLatestRoot();
+        Root theirs = login(getAdminCredentials()).getLatestRoot();
+
+        rm(ours, users[1].getID());
+        rm(theirs, users[2].getID());
+
+        root.refresh();
+        assertTrue(group.isDeclaredMember(users[0]));
+        assertFalse(group.isDeclaredMember(users[1]));
+        assertFalse(group.isDeclaredMember(users[2]));
+    }
+
+    /**
+     * Remove-Add with different ids test
+     */
+    @Test
+    public void changeChangedPropertyRA() throws Exception {
+        add(root, users[0].getID(), users[1].getID());
+
+        Root ours = login(getAdminCredentials()).getLatestRoot();
+        Root theirs = login(getAdminCredentials()).getLatestRoot();
+
+        rm(ours, users[1].getID());
+        add(theirs, users[2].getID());
+
+        root.refresh();
+        assertTrue(group.isDeclaredMember(users[0]));
+        assertFalse(group.isDeclaredMember(users[1]));
+        assertTrue(group.isDeclaredMember(users[2]));
+    }
+
+    /**
+     * Add-Remove with different ids test
+     */
+    @Test
+    public void changeChangedPropertyAR() throws Exception {
+        add(root, users[0].getID(), users[1].getID());
+
+        Root ours = login(getAdminCredentials()).getLatestRoot();
+        Root theirs = login(getAdminCredentials()).getLatestRoot();
+
+        add(ours, users[2].getID());
+        rm(theirs, users[1].getID());
+
+        root.refresh();
+        assertTrue(group.isDeclaredMember(users[0]));
+        assertFalse(group.isDeclaredMember(users[1]));
+        assertTrue(group.isDeclaredMember(users[2]));
+    }
+
+    /**
+     * Remove-Add same value test. value was already part of the group
+     */
+    @Test
+    public void changeChangedPropertyRA2() throws Exception {
+        add(root, users[0].getID(), users[1].getID());
+
+        Root ours = login(getAdminCredentials()).getLatestRoot();
+        Root theirs = login(getAdminCredentials()).getLatestRoot();
+
+        String id = users[1].getID();
+        rm(ours, id);
+        add(theirs, id);
+
+        root.refresh();
+        assertTrue(group.isDeclaredMember(users[0]));
+        assertFalse(group.isDeclaredMember(users[1]));
+    }
+
+    /**
+     * Add-Remove same value test. value was already part of the group
+     */
+    @Test
+    public void changeChangedPropertyAR2() throws Exception {
+        add(root, users[0].getID(), users[1].getID());
+
+        Root ours = login(getAdminCredentials()).getLatestRoot();
+        Root theirs = login(getAdminCredentials()).getLatestRoot();
+
+        String id = users[1].getID();
+        add(ours, id);
+        rm(theirs, id);
+
+        root.refresh();
+        assertTrue(group.isDeclaredMember(users[0]));
+        assertFalse(group.isDeclaredMember(users[1]));
+    }
+
+    /**
+     * Remove-Add same value test. value was not part of the group
+     */
+    @Test
+    public void changeChangedPropertyRA3() throws Exception {
+        add(root, users[0].getID(), users[1].getID());
+
+        Root ours = login(getAdminCredentials()).getLatestRoot();
+        Root theirs = login(getAdminCredentials()).getLatestRoot();
+
+        String id = users[2].getID();
+        // we are removing an item that does not yet exist, this should
+        // not overlap/conflict with the other session adding the same item
+        rm(ours, id);
+        add(theirs, id);
+
+        root.refresh();
+        assertTrue(group.isDeclaredMember(users[0]));
+        assertTrue(group.isDeclaredMember(users[1]));
+        assertTrue(group.isDeclaredMember(users[2]));
+    }
+
+    /**
+     * Add-Remove same value test. value was not part of the group
+     */
+    @Test
+    public void changeChangedPropertyAR3() throws Exception {
+        add(root, users[0].getID(), users[1].getID());
+
+        Root ours = login(getAdminCredentials()).getLatestRoot();
+        Root theirs = login(getAdminCredentials()).getLatestRoot();
+
+        String id = users[2].getID();
+        add(ours, id);
+        // we are removing an item that does not yet exist, this should
+        // not overlap/conflict with the other session adding the same item
+        rm(theirs, id);
+
+        root.refresh();
+        assertTrue(group.isDeclaredMember(users[0]));
+        assertTrue(group.isDeclaredMember(users[1]));
+        assertTrue(group.isDeclaredMember(users[2]));
+    }
+
+    /**
+     * Delete-Changed. Delete takes precedence
+     */
+    @Test
+    public void deleteChangedProperty() throws Exception {
+        add(root, users[0].getID(), users[1].getID());
+
+        Root ours = login(getAdminCredentials()).getLatestRoot();
+        Root theirs = login(getAdminCredentials()).getLatestRoot();
+
+        add(theirs, users[2].getID());
+        wipeGroup(ours);
+
+        root.refresh();
+        assertFalse(group.isDeclaredMember(users[0]));
+        assertFalse(group.isDeclaredMember(users[1]));
+    }
+
+    /**
+     * Changed-Deleted. Delete takes precedence
+     */
+    @Test
+    public void changeDeletedProperty() throws Exception {
+        add(root, users[0].getID(), users[1].getID());
+
+        Root ours = login(getAdminCredentials()).getLatestRoot();
+        Root theirs = login(getAdminCredentials()).getLatestRoot();
+
+        wipeGroup(theirs);
+        add(ours, users[2].getID());
+
+        root.refresh();
+        assertFalse(group.isDeclaredMember(users[0]));
+        assertFalse(group.isDeclaredMember(users[1]));
+    }
+
+    private void add(Root r, String... ids) throws Exception {
+        UserManager um = getUserManager(r);
+        Group g = (Group) um.getAuthorizable(GROUP_ID);
+        for (String id : ids) {
+            g.addMember(um.getAuthorizable(id));
+        }
+        r.commit();
+    }
+
+    private void rm(Root r, String... ids) throws Exception {
+        UserManager um = getUserManager(r);
+        Group g = (Group) um.getAuthorizable(GROUP_ID);
+        for (String id : ids) {
+            g.removeMember(um.getAuthorizable(id));
+        }
+        r.commit();
+    }
+
+    private void wipeGroup(Root r) throws Exception {
+        UserManager um = getUserManager(r);
+        Group g = (Group) um.getAuthorizable(GROUP_ID);
+        r.getTree(g.getPath()).removeProperty(UserConstants.REP_MEMBERS);
+        r.commit();
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RepMembersConflictHandlerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java?rev=1800179&r1=1800178&r2=1800179&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java
 Wed Jun 28 15:03:41 2017
@@ -21,6 +21,7 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import com.google.common.collect.ImmutableList;
+import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
 import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter;
 import org.junit.Before;
 import org.junit.Test;
@@ -193,7 +194,7 @@ public class CompositeConfigurationTest
     }
 
     @Test
-    public void testGetProtectedItemImporter() {
+    public void testGetProtectedItemImporters() {
         
assertTrue(compositeConfiguration.getProtectedItemImporters().isEmpty());
 
         addConfiguration(new SecurityConfiguration.Default());
@@ -210,4 +211,24 @@ public class CompositeConfigurationTest
 
         assertEquals(1, 
compositeConfiguration.getProtectedItemImporters().size());
     }
+
+
+    @Test
+    public void testGetConflictHandlers() {
+        assertTrue(compositeConfiguration.getConflictHandlers().isEmpty());
+
+        addConfiguration(new SecurityConfiguration.Default());
+        assertTrue(compositeConfiguration.getConflictHandlers().isEmpty());
+
+        SecurityConfiguration withConflictHandler = new 
SecurityConfiguration.Default() {
+            @Nonnull
+            @Override
+            public List<ThreeWayConflictHandler> getConflictHandlers() {
+                return 
ImmutableList.of(Mockito.mock(ThreeWayConflictHandler.class));
+            }
+        };
+        addConfiguration(withConflictHandler);
+
+        assertEquals(1, compositeConfiguration.getConflictHandlers().size());
+    }
 }
\ No newline at end of file


Reply via email to