You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by dj...@apache.org on 2016/08/18 13:15:23 UTC

svn commit: r1756777 [2/4] - in /jackrabbit/oak/branches/1.2: ./ oak-auth-external/ oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/ oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/secu...

Modified: jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java Thu Aug 18 13:15:22 2016
@@ -24,8 +24,7 @@ import javax.security.auth.login.LoginEx
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.oak.api.ContentSession;
-import org.apache.jackrabbit.oak.namepath.NamePathMapper;
-import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncContext;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -43,12 +42,6 @@ public class ExternalLoginModuleTest ext
 
     protected final HashMap<String, Object> options = new HashMap<String, Object>();
 
-    private final String userId = "testUser";
-
-    private final static String TEST_CONSTANT_PROPERTY_NAME = "profile/constantProperty";
-
-    private final static String TEST_CONSTANT_PROPERTY_VALUE = "constant-value";
-
     @Before
     public void before() throws Exception {
         super.before();
@@ -59,15 +52,6 @@ public class ExternalLoginModuleTest ext
         super.after();
     }
 
-    protected ExternalIdentityProvider createIDP() {
-        return new TestIdentityProvider();
-    }
-
-    @Override
-    protected void destroyIDP(ExternalIdentityProvider idp) {
-    // ignore
-    }
-
     @Test
     public void testLoginFailed() throws Exception {
         UserManager userManager = getUserManager(root);
@@ -78,7 +62,7 @@ public class ExternalLoginModuleTest ext
         } catch (LoginException e) {
             // success
         } finally {
-            assertNull(userManager.getAuthorizable(userId));
+            assertNull(userManager.getAuthorizable(USER_ID));
         }
     }
 
@@ -87,15 +71,15 @@ public class ExternalLoginModuleTest ext
         UserManager userManager = getUserManager(root);
         ContentSession cs = null;
         try {
-            assertNull(userManager.getAuthorizable(userId));
+            assertNull(userManager.getAuthorizable(USER_ID));
 
-            cs = login(new SimpleCredentials(userId, new char[0]));
+            cs = login(new SimpleCredentials(USER_ID, new char[0]));
 
             root.refresh();
 
-            Authorizable a = userManager.getAuthorizable(userId);
+            Authorizable a = userManager.getAuthorizable(USER_ID);
             assertNotNull(a);
-            ExternalUser user = idp.getUser(userId);
+            ExternalUser user = idp.getUser(USER_ID);
             for (String prop : user.getProperties().keySet()) {
                 assertTrue(a.hasProperty(prop));
             }
@@ -113,15 +97,15 @@ public class ExternalLoginModuleTest ext
         UserManager userManager = getUserManager(root);
         ContentSession cs = null;
         try {
-            assertNull(userManager.getAuthorizable(userId));
+            assertNull(userManager.getAuthorizable(USER_ID));
 
-            cs = login(new SimpleCredentials(userId.toUpperCase(), new char[0]));
+            cs = login(new SimpleCredentials(USER_ID.toUpperCase(), new char[0]));
 
             root.refresh();
 
-            Authorizable a = userManager.getAuthorizable(userId);
+            Authorizable a = userManager.getAuthorizable(USER_ID);
             assertNotNull(a);
-            ExternalUser user = idp.getUser(userId);
+            ExternalUser user = idp.getUser(USER_ID);
             for (String prop : user.getProperties().keySet()) {
                 assertTrue(a.hasProperty(prop));
             }
@@ -139,7 +123,7 @@ public class ExternalLoginModuleTest ext
         UserManager userManager = getUserManager(root);
         ContentSession cs = null;
         try {
-            cs = login(new SimpleCredentials(userId, new char[0]));
+            cs = login(new SimpleCredentials(USER_ID, new char[0]));
 
             root.refresh();
             for (String id : new String[]{"a", "b", "c"}) {
@@ -162,7 +146,7 @@ public class ExternalLoginModuleTest ext
         UserManager userManager = getUserManager(root);
         ContentSession cs = null;
         try {
-            cs = login(new SimpleCredentials(userId, new char[0]));
+            cs = login(new SimpleCredentials(USER_ID, new char[0]));
 
             root.refresh();
             for (String id : new String[]{"a", "b", "c", "aa", "aaa"}) {
@@ -180,18 +164,18 @@ public class ExternalLoginModuleTest ext
     public void testSyncUpdate() throws Exception {
         // create user upfront in order to test update mode
         UserManager userManager = getUserManager(root);
-        ExternalUser externalUser = idp.getUser(userId);
+        ExternalUser externalUser = idp.getUser(USER_ID);
         Authorizable user = userManager.createUser(externalUser.getId(), null);
-        user.setProperty("rep:externalId", new ValueFactoryImpl(root, NamePathMapper.DEFAULT).createValue(externalUser.getExternalId().getString()));
+        user.setProperty(DefaultSyncContext.REP_EXTERNAL_ID, getValueFactory().createValue(externalUser.getExternalId().getString()));
         root.commit();
 
         ContentSession cs = null;
         try {
-            cs = login(new SimpleCredentials(userId, new char[0]));
+            cs = login(new SimpleCredentials(USER_ID, new char[0]));
 
             root.refresh();
 
-            Authorizable a = userManager.getAuthorizable(userId);
+            Authorizable a = userManager.getAuthorizable(USER_ID);
             assertNotNull(a);
             for (String prop : externalUser.getProperties().keySet()) {
                 assertTrue(a.hasProperty(prop));

Modified: jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTestBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTestBase.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTestBase.java (original)
+++ jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTestBase.java Thu Aug 18 13:15:22 2016
@@ -19,17 +19,9 @@ package org.apache.jackrabbit.oak.spi.se
 
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
 import javax.security.auth.login.AppConfigurationEntry;
 import javax.security.auth.login.Configuration;
 
-import org.apache.jackrabbit.api.security.user.Authorizable;
-import org.apache.jackrabbit.api.security.user.UserManager;
-import org.apache.jackrabbit.oak.AbstractSecurityTest;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncConfig;
 import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncHandler;
@@ -43,81 +35,43 @@ import org.junit.After;
 import org.junit.Before;
 
 /**
- * ExternalLoginModuleTest...
+ * Abstract base test for external-authentication including proper OSGi service
+ * registrations required for repository login respecting the {@link ExternalLoginModule}.
  */
-public abstract class ExternalLoginModuleTestBase extends AbstractSecurityTest {
-
-    private Set<String> ids = new HashSet<String>();
+public abstract class ExternalLoginModuleTestBase extends AbstractExternalAuthTest {
 
     private Registration testIdpReg;
-
     private Registration syncHandlerReg;
 
     protected final HashMap<String, Object> options = new HashMap<String, Object>();
 
     protected Whiteboard whiteboard;
 
-    protected ExternalIdentityProvider idp;
-
     protected SyncManager syncManager;
 
     protected ExternalIdentityProviderManager idpManager;
 
-    protected DefaultSyncConfig syncConfig;
-
     @Before
     public void before() throws Exception {
         super.before();
-        UserManager userManager = getUserManager(root);
-        Iterator<Authorizable> iter = userManager.findAuthorizables("jcr:primaryType", null);
-        while (iter.hasNext()) {
-            ids.add(iter.next().getID());
-        }
-        idp = createIDP();
 
         testIdpReg = whiteboard.register(ExternalIdentityProvider.class, idp, Collections.<String, Object>emptyMap());
 
         options.put(ExternalLoginModule.PARAM_SYNC_HANDLER_NAME, "default");
         options.put(ExternalLoginModule.PARAM_IDP_NAME, idp.getName());
 
-        // set default sync config
-        syncConfig = new DefaultSyncConfig();
-        Map<String, String> mapping = new HashMap<String, String>();
-        mapping.put("name", "name");
-        mapping.put("email", "email");
-        mapping.put("profile/name", "profile/name");
-        mapping.put("profile/age", "profile/age");
-        mapping.put("profile/constantProperty", "\"constant-value\"");
-        syncConfig.user().setPropertyMapping(mapping);
-        syncConfig.user().setMembershipNestingDepth(1);
         setSyncConfig(syncConfig);
     }
 
     @After
     public void after() throws Exception {
-        if (testIdpReg != null) {
-            testIdpReg.unregister();
-            testIdpReg = null;
-        }
-        destroyIDP(idp);
-        idp = null;
-        setSyncConfig(null);
-
         try {
-            UserManager userManager = getUserManager(root);
-            Iterator<Authorizable> iter = userManager.findAuthorizables("jcr:primaryType", null);
-            while (iter.hasNext()) {
-                ids.remove(iter.next().getID());
-            }
-            for (String id : ids) {
-                Authorizable a = userManager.getAuthorizable(id);
-                if (a != null) {
-                    a.remove();
-                }
+            if (testIdpReg != null) {
+                testIdpReg.unregister();
+                testIdpReg = null;
             }
-            root.commit();
+            setSyncConfig(null);
         } finally {
-            root.refresh();
             super.after();
         }
     }
@@ -136,12 +90,8 @@ public abstract class ExternalLoginModul
         return oak;
     }
 
-    protected abstract ExternalIdentityProvider createIDP();
-
-    protected abstract void destroyIDP(ExternalIdentityProvider idp);
-
     protected SynchronizationMBean createMBean() {
-        // todo: how to retrieve JCR repository here? maybe we should base the sync mbean on oak directly.
+        // todo: how to retrieve JCR repository here? maybe we should base the sync mbean on oak directly (=> OAK-4218).
         // JackrabbitRepository repository =  null;
         // return new SyncMBeanImpl(repository, syncManager, "default", idpManager, idp.getName());
 

Modified: jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestIdentityProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestIdentityProvider.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestIdentityProvider.java (original)
+++ jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestIdentityProvider.java Thu Aug 18 13:15:22 2016
@@ -27,26 +27,58 @@ import javax.jcr.Credentials;
 import javax.jcr.SimpleCredentials;
 import javax.security.auth.login.LoginException;
 
+import com.google.common.collect.ImmutableList;
+
 public class TestIdentityProvider implements ExternalIdentityProvider {
 
+    public static final String ID_TEST_USER = "testUser";
+    public static final String ID_SECOND_USER = "secondUser";
+    public static final String ID_WILDCARD_USER = "wildcardUser";
+
+    public static final String ID_EXCEPTION = "throw!";
+
+    public static final String DEFAULT_IDP_NAME = "test";
+
     private final Map<String, ExternalGroup> externalGroups = new HashMap<String, ExternalGroup>();
     private final Map<String, ExternalUser> externalUsers = new HashMap<String, ExternalUser>();
 
+    private final String idpName;
 
     public TestIdentityProvider() {
-        addGroup(new TestGroup("aa"));
-        addGroup(new TestGroup("aaa"));
-        addGroup(new TestGroup("a").withGroups("aa", "aaa"));
-        addGroup(new TestGroup("b").withGroups("a"));
-        addGroup(new TestGroup("c"));
+        this(DEFAULT_IDP_NAME);
+    }
+
+    public TestIdentityProvider(@Nonnull String idpName) {
+        this.idpName = idpName;
 
-        addUser(new TestUser("testUser")
+        addGroup(new TestGroup("aa", getName()));
+        addGroup(new TestGroup("aaa", getName()));
+        addGroup(new TestGroup("a", getName()).withGroups("aa", "aaa"));
+        addGroup(new TestGroup("b", getName()).withGroups("a"));
+        addGroup(new TestGroup("c", getName()));
+        addGroup(new TestGroup("secondGroup", getName()));
+        addGroup(new TestGroup("_gr_u_", getName()));
+        addGroup(new TestGroup("g%r%", getName()));
+
+        addUser(new TestUser(ID_TEST_USER, getName())
                 .withProperty("name", "Test User")
                 .withProperty("profile/name", "Public Name")
                 .withProperty("profile/age", 72)
                 .withProperty("email", "test@testuser.com")
                 .withGroups("a", "b", "c")
         );
+
+        addUser(new TestUser(ID_SECOND_USER, getName())
+                .withProperty("profile/name", "Second User")
+                .withProperty("age", 24)
+                .withProperty("col", ImmutableList.of("v1", "v2", "v3"))
+                .withProperty("boolArr", new Boolean[]{true, false})
+                .withProperty("charArr", new char[]{'t', 'o', 'b'})
+                .withProperty("byteArr", new byte[0])
+                .withGroups("secondGroup"));
+
+        addUser(new TestUser(ID_WILDCARD_USER, getName())
+                .withGroups("_gr_u_", "g%r%"));
     }
 
     private void addUser(TestIdentity user) {
@@ -60,11 +92,15 @@ public class TestIdentityProvider implem
     @Nonnull
     @Override
     public String getName() {
-        return "test";
+        return idpName;
     }
 
     @Override
     public ExternalIdentity getIdentity(@Nonnull ExternalIdentityRef ref) throws ExternalIdentityException {
+        if (ID_EXCEPTION.equals(ref.getId())) {
+            throw new ExternalIdentityException(ID_EXCEPTION);
+        }
+
         ExternalIdentity id = externalUsers.get(ref.getId().toLowerCase());
         if (id != null) {
             return id;
@@ -74,6 +110,9 @@ public class TestIdentityProvider implem
 
     @Override
     public ExternalUser getUser(@Nonnull String userId) throws ExternalIdentityException {
+        if (ID_EXCEPTION.equals(userId)) {
+            throw new ExternalIdentityException(ID_EXCEPTION);
+        }
         return externalUsers.get(userId.toLowerCase());
     }
 
@@ -94,6 +133,9 @@ public class TestIdentityProvider implem
 
     @Override
     public ExternalGroup getGroup(@Nonnull String name) throws ExternalIdentityException {
+        if (ID_EXCEPTION.equals(name)) {
+            throw new ExternalIdentityException(ID_EXCEPTION);
+        }
         return externalGroups.get(name.toLowerCase());
     }
 
@@ -109,17 +151,33 @@ public class TestIdentityProvider implem
         return externalGroups.values().iterator();
     }
 
-    private static class TestIdentity implements ExternalIdentity {
+    public static class TestIdentity implements ExternalIdentity {
 
         private final String userId;
+        private final String principalName;
         private final ExternalIdentityRef id;
 
         private final Set<ExternalIdentityRef> groups = new HashSet<ExternalIdentityRef>();
         private final Map<String, Object> props = new HashMap<String, Object>();
 
-        private TestIdentity(String userId) {
+        public TestIdentity() {
+            this("externalId", "principalName", DEFAULT_IDP_NAME);
+        }
+
+        public TestIdentity(@Nonnull String userId) {
+            this(userId, userId, DEFAULT_IDP_NAME);
+        }
+
+        public TestIdentity(@Nonnull String userId, @Nonnull String principalName, @Nonnull String idpName) {
             this.userId = userId;
-            id = new ExternalIdentityRef(userId, "test");
+            this.principalName = principalName;
+            id = new ExternalIdentityRef(userId, idpName);
+        }
+
+        public TestIdentity(@Nonnull ExternalIdentity base) {
+            userId = base.getId();
+            principalName = base.getPrincipalName();
+            id = base.getExternalId();
         }
 
         @Nonnull
@@ -131,7 +189,7 @@ public class TestIdentityProvider implem
         @Nonnull
         @Override
         public String getPrincipalName() {
-            return userId;
+            return principalName;
         }
 
         @Nonnull
@@ -164,16 +222,16 @@ public class TestIdentityProvider implem
 
         protected TestIdentity withGroups(String ... grps) {
             for (String grp: grps) {
-                groups.add(new ExternalIdentityRef(grp, "test"));
+                groups.add(new ExternalIdentityRef(grp, id.getProviderName()));
             }
             return this;
         }
     }
 
-    private static class TestUser extends TestIdentity implements ExternalUser {
+    public static class TestUser extends TestIdentity implements ExternalUser {
 
-        private TestUser(String userId) {
-            super(userId);
+        public TestUser(String userId, @Nonnull String idpName) {
+            super(userId, userId, idpName);
         }
 
         public String getPassword() {
@@ -182,10 +240,10 @@ public class TestIdentityProvider implem
 
     }
 
-    private static class TestGroup extends TestIdentity implements ExternalGroup {
+    public static class TestGroup extends TestIdentity implements ExternalGroup {
 
-        private TestGroup(String userId) {
-            super(userId);
+        public TestGroup(@Nonnull String userId, @Nonnull String idpName) {
+            super(userId, userId, idpName);
         }
 
         @Nonnull
@@ -194,4 +252,24 @@ public class TestIdentityProvider implem
             return null;
         }
     }
+
+    public static final class ForeignExternalUser extends TestIdentityProvider.TestIdentity implements ExternalUser {
+
+        public ForeignExternalUser() {
+            super("externalId", "principalName", "AnotherExternalIDP");
+        }
+    }
+
+    public static final class ForeignExternalGroup extends TestIdentityProvider.TestIdentity implements ExternalGroup {
+
+        public ForeignExternalGroup() {
+            super("externalId", "principalName", "AnotherExternalIDP");
+        }
+
+        @Nonnull
+        @Override
+        public Iterable<ExternalIdentityRef> getDeclaredMembers() {
+            return ImmutableList.of();
+        }
+    }
 }
\ No newline at end of file

Copied: jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestSecurityProvider.java (from r1744292, jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestSecurityProvider.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestSecurityProvider.java?p2=jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestSecurityProvider.java&p1=jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestSecurityProvider.java&r1=1744292&r2=1756777&rev=1756777&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestSecurityProvider.java (original)
+++ jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestSecurityProvider.java Thu Aug 18 13:15:22 2016
@@ -27,7 +27,8 @@ import org.apache.jackrabbit.oak.spi.sec
 import static com.google.common.base.Preconditions.checkNotNull;
 
 public class TestSecurityProvider extends SecurityProviderImpl {
-    public TestSecurityProvider(@Nonnull ConfigurationParameters configuration) {
+
+    public TestSecurityProvider(@Nonnull ConfigurationParameters configuration, @Nonnull ExternalPrincipalConfiguration externalPrincipalConfiguration) {
         super(configuration);
 
         PrincipalConfiguration principalConfiguration = getConfiguration(PrincipalConfiguration.class);
@@ -35,7 +36,7 @@ public class TestSecurityProvider extend
             throw new IllegalStateException();
         } else {
             PrincipalConfiguration defConfig = checkNotNull(((CompositePrincipalConfiguration) principalConfiguration).getDefaultConfig());
-            bindPrincipalConfiguration((new ExternalPrincipalConfiguration(this)));
+            bindPrincipalConfiguration(externalPrincipalConfiguration);
             bindPrincipalConfiguration(defConfig);
         }
     }

Modified: jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncContextTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncContextTest.java?rev=1756777&r1=1711209&r2=1756777&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncContextTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncContextTest.java Thu Aug 18 13:15:22 2016
@@ -16,94 +16,257 @@
  */
 package org.apache.jackrabbit.oak.spi.security.authentication.external.basic;
 
-import java.util.ArrayList;
-import java.util.Iterator;
+import java.io.ByteArrayInputStream;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
-import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import javax.jcr.Binary;
+import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterators;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import org.apache.jackrabbit.api.security.user.Authorizable;
 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.namepath.NamePathMapper;
-import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.AbstractExternalAuthTest;
 import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalGroup;
 import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentity;
 import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityRef;
 import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalUser;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncException;
 import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncResult;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncedIdentity;
 import org.apache.jackrabbit.oak.spi.security.authentication.external.TestIdentityProvider;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
-public class DefaultSyncContextTest extends AbstractSecurityTest {
-
-    private TestIdentityProvider idp = new TestIdentityProvider();
-    private DefaultSyncConfig config = new DefaultSyncConfig();
+public class DefaultSyncContextTest extends AbstractExternalAuthTest {
 
+    private UserManager userManager;
+    private ValueFactory valueFactory;
     private DefaultSyncContext syncCtx;
 
-    private List<String> authorizableIds = new ArrayList<String>();
-
     @Before
     public void before() throws Exception {
         super.before();
-        syncCtx = new DefaultSyncContext(config, idp, getUserManager(root), new ValueFactoryImpl(root, NamePathMapper.DEFAULT));
+        userManager = getUserManager(root);
+        valueFactory = getValueFactory();
+        syncCtx = new DefaultSyncContext(syncConfig, idp, userManager, valueFactory);
     }
 
     @After
     public void after() throws Exception {
         try {
             syncCtx.close();
-            UserManager umgr = getUserManager(root);
-            Iterator<ExternalIdentity> ids = Iterators.concat(idp.listGroups(), idp.listUsers());
-            while (ids.hasNext()) {
-                Authorizable a = umgr.getAuthorizable(ids.next().getId());
-                if (a != null) {
-                    a.remove();
-                }
-            }
-            for (String id : authorizableIds) {
-                Authorizable a = umgr.getAuthorizable(id);
-                if (a != null) {
-                    a.remove();
-                }
-            }
-            root.commit();
+            root.refresh();
         } finally {
             super.after();
         }
     }
 
+    @Override
+    protected DefaultSyncConfig createSyncConfig() {
+        return new DefaultSyncConfig();
+    }
+
     private Group createTestGroup() throws Exception {
-        Group gr = getUserManager(root).createGroup("group" + UUID.randomUUID());
-        authorizableIds.add(gr.getID());
-        return gr;
+        return userManager.createGroup("group" + UUID.randomUUID());
+    }
+
+    /**
+     * Test utility method to synchronize the given identity into the repository.
+     * This is intended to simplify those tests that require a given user/group
+     * to be synchronized before executing the test.
+     *
+     * @param externalIdentity The external identity to be synchronized.
+     * @throws Exception
+     */
+    private void sync(@Nonnull ExternalIdentity externalIdentity) throws Exception {
+        SyncResult result = syncCtx.sync(externalIdentity);
+        assertSame(SyncResult.Status.ADD, result.getStatus());
+        root.commit();
     }
 
     private void setExternalID(@Nonnull Authorizable authorizable, @Nullable String idpName) throws RepositoryException {
-        authorizable.setProperty(DefaultSyncContext.REP_EXTERNAL_ID, getValueFactory().createValue(authorizable.getID() + ';' + idpName));
+        authorizable.setProperty(DefaultSyncContext.REP_EXTERNAL_ID, valueFactory.createValue(authorizable.getID() + ';' + idpName));
+    }
+
+    @Test
+    public void testCreateSyncedIdentityNull() throws Exception {
+        assertNull(DefaultSyncContext.createSyncedIdentity(null));
+    }
+
+    @Test
+    public void testCreateSyncedIdentityLocalGroup() throws Exception {
+        Group gr = createTestGroup();
+        SyncedIdentity si = DefaultSyncContext.createSyncedIdentity(gr);
+
+        assertNotNull(si);
+        assertEquals(gr.getID(), si.getId());
+        assertNull(si.getExternalIdRef());
+        assertTrue(si.isGroup());
+        assertEquals(-1, si.lastSynced());
+    }
+
+    @Test
+    public void testCreateSyncedIdentityLocalUser() throws Exception {
+        User u = getTestUser();
+        SyncedIdentity si = DefaultSyncContext.createSyncedIdentity(u);
+
+        assertNotNull(si);
+        assertEquals(u.getID(), si.getId());
+        assertNull(si.getExternalIdRef());
+        assertFalse(si.isGroup());
+        assertEquals(-1, si.lastSynced());
+    }
+
+    @Test
+    public void testCreateSyncedIdentitySyncedGroup() throws Exception {
+        ExternalIdentity externalGroup = idp.listGroups().next();
+        sync(externalGroup);
+
+        Authorizable a = userManager.getAuthorizable(externalGroup.getId());
+        SyncedIdentity si = DefaultSyncContext.createSyncedIdentity(a);
+
+        assertNotNull(si);
+        assertEquals(a.getID(), si.getId());
+        assertNotNull(si.getExternalIdRef());
+        assertTrue(si.isGroup());
+        assertEquals(syncCtx.now, si.lastSynced());
+    }
+
+    @Test
+    public void testCreateSyncedIdentitySyncedUser() throws Exception {
+        ExternalIdentity externalUser = idp.listUsers().next();
+        sync(externalUser);
+
+        Authorizable a = userManager.getAuthorizable(externalUser.getId());
+        SyncedIdentity si = DefaultSyncContext.createSyncedIdentity(a);
+
+        assertNotNull(si);
+        assertEquals(a.getID(), si.getId());
+        assertNotNull(si.getExternalIdRef());
+        assertFalse(si.isGroup());
+        assertEquals(syncCtx.now, si.lastSynced());
+    }
+
+    @Test
+    public void testCreateSyncedIdentityEmptyLastSyncedProperty() throws Exception {
+        Group gr = createTestGroup();
+        gr.setProperty(DefaultSyncContext.REP_LAST_SYNCED, new Value[0]);
+
+        SyncedIdentity si = DefaultSyncContext.createSyncedIdentity(gr);
+        assertNotNull(si);
+        assertEquals(-1, si.lastSynced());
+    }
+
+    @Test
+    public void testGetIdentityRefNull() throws Exception {
+        assertNull(DefaultSyncContext.getIdentityRef(null));
+    }
+
+    @Test
+    public void testGetIdentityRefLocalGroup() throws Exception {
+        assertNull(DefaultSyncContext.getIdentityRef(createTestGroup()));
+    }
+
+    @Test
+    public void testGetIdentityRefLocalUser() throws Exception {
+        assertNull(DefaultSyncContext.getIdentityRef(getTestUser()));
+    }
+
+    @Test
+    public void testGetIdentityRefSyncGroup() throws Exception {
+        ExternalIdentity externalGroup = idp.listGroups().next();
+        sync(externalGroup);
+
+        ExternalIdentityRef ref = DefaultSyncContext.getIdentityRef(userManager.getAuthorizable(externalGroup.getId()));
+        assertNotNull(ref);
+        assertEquals(externalGroup.getExternalId(), ref);
+    }
+
+    @Test
+    public void testGetIdentityRefSyncUser() throws Exception {
+        ExternalIdentity externalUser = idp.listUsers().next();
+        sync(externalUser);
+
+        ExternalIdentityRef ref = DefaultSyncContext.getIdentityRef(userManager.getAuthorizable(externalUser.getId()));
+        assertNotNull(ref);
+        assertEquals(externalUser.getExternalId(), ref);
+    }
+
+    @Test
+    public void testGetIdentityRefEmptyMvProperty() throws Exception {
+        Group gr = createTestGroup();
+        // NOTE: making rep:externalId a multivalue property without any value
+        //       not committing the changes as this prop is expected to become
+        //       protected to prevent unintentional or malicious modification.
+        gr.setProperty(DefaultSyncContext.REP_EXTERNAL_ID, new Value[0]);
+
+        ExternalIdentityRef ref = DefaultSyncContext.getIdentityRef(gr);
+        assertNull(ref);
+    }
+
+    @Test
+    public void testIsKeepMissing() {
+        assertFalse(syncCtx.isKeepMissing());
+
+        assertSame(syncCtx, syncCtx.setKeepMissing(true));
+        assertTrue(syncCtx.isKeepMissing());
+
+        assertSame(syncCtx, syncCtx.setKeepMissing(false));
+        assertFalse(syncCtx.isKeepMissing());
+    }
+
+    @Test
+    public void testIsForceUserSync() {
+        assertFalse(syncCtx.isForceUserSync());
+
+        assertSame(syncCtx, syncCtx.setForceUserSync(true));
+        assertTrue(syncCtx.isForceUserSync());
+
+        assertSame(syncCtx, syncCtx.setForceUserSync(false));
+        assertFalse(syncCtx.isForceUserSync());
+    }
+
+    @Test
+    public void testIsForceGroupSync() {
+        assertFalse(syncCtx.isForceGroupSync());
+
+        assertSame(syncCtx, syncCtx.setForceGroupSync(true));
+        assertTrue(syncCtx.isForceGroupSync());
+
+        assertSame(syncCtx, syncCtx.setForceGroupSync(false));
+        assertFalse(syncCtx.isForceGroupSync());
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testSyncInvalidExternalIdentity() throws Exception {
-        syncCtx.sync(new TestExternalIdentity());
+        syncCtx.sync(new TestIdentityProvider.TestIdentity());
     }
 
     @Test
@@ -140,6 +303,50 @@ public class DefaultSyncContextTest exte
     }
 
     @Test
+    public void testSyncForeignExternalUser() throws Exception {
+        ExternalIdentity foreign = new TestIdentityProvider.ForeignExternalUser();
+
+        SyncResult res = syncCtx.sync(foreign);
+        assertNotNull(res);
+        assertSame(SyncResult.Status.FOREIGN, res.getStatus());
+
+        // expect {@code SyncedIdentity} in accordance with {@code sync(String userId)},
+        // where the authorizable is found to be linked to a different IDP.
+        SyncedIdentity si = res.getIdentity();
+        assertNotNull(si);
+        assertEquals(foreign.getId(), si.getId());
+        ExternalIdentityRef ref = si.getExternalIdRef();
+        assertNotNull(ref);
+        assertEquals(foreign.getExternalId(), ref);
+        assertFalse(si.isGroup());
+        assertEquals(-1, si.lastSynced());
+
+        assertFalse(root.hasPendingChanges());
+    }
+
+    @Test
+    public void testSyncForeignExternalGroup() throws Exception {
+        ExternalIdentity foreign = new TestIdentityProvider.ForeignExternalGroup();
+
+        SyncResult res = syncCtx.sync(foreign);
+        assertNotNull(res);
+        assertSame(SyncResult.Status.FOREIGN, res.getStatus());
+
+        // expect {@code SyncedIdentity} in accordance with {@code sync(String userId)},
+        // where the authorizable is found to be linked to a different IDP.
+        SyncedIdentity si = res.getIdentity();
+        assertNotNull(si);
+        assertEquals(foreign.getId(), si.getId());
+        ExternalIdentityRef ref = si.getExternalIdRef();
+        assertNotNull(ref);
+        assertEquals(foreign.getExternalId(), ref);
+        assertTrue(si.isGroup());
+        assertEquals(-1, si.lastSynced());
+
+        assertFalse(root.hasPendingChanges());
+    }
+
+    @Test
     public void testSyncUserById() throws Exception {
         ExternalIdentity externalId = idp.listUsers().next();
 
@@ -159,24 +366,22 @@ public class DefaultSyncContextTest exte
     @Test
     public void testSyncRemovedUserById() throws Exception {
         // mark a regular repo user as external user from the test IDP
-        User u = getUserManager(root).createUser("test" + UUID.randomUUID(), null);
+        User u = userManager.createUser("test" + UUID.randomUUID(), null);
         String userId = u.getID();
-        authorizableIds.add(userId);
-
         setExternalID(u, idp.getName());
 
         // test sync with 'keepmissing' = true
         syncCtx.setKeepMissing(true);
         SyncResult result = syncCtx.sync(userId);
         assertEquals(SyncResult.Status.MISSING, result.getStatus());
-        assertNotNull(getUserManager(root).getAuthorizable(userId));
+        assertNotNull(userManager.getAuthorizable(userId));
 
         // test sync with 'keepmissing' = false
         syncCtx.setKeepMissing(false);
         result = syncCtx.sync(userId);
         assertEquals(SyncResult.Status.DELETE, result.getStatus());
 
-        assertNull(getUserManager(root).getAuthorizable(userId));
+        assertNull(userManager.getAuthorizable(userId));
     }
 
     @Test
@@ -208,14 +413,14 @@ public class DefaultSyncContextTest exte
         syncCtx.setKeepMissing(true);
         SyncResult result = syncCtx.sync(groupId);
         assertEquals(SyncResult.Status.MISSING, result.getStatus());
-        assertNotNull(getUserManager(root).getAuthorizable(groupId));
+        assertNotNull(userManager.getAuthorizable(groupId));
 
         // test sync with 'keepmissing' = false
         syncCtx.setKeepMissing(false);
         result = syncCtx.sync(groupId);
         assertEquals(SyncResult.Status.DELETE, result.getStatus());
 
-        assertNull(getUserManager(root).getAuthorizable(groupId));
+        assertNull(userManager.getAuthorizable(groupId));
     }
 
     @Test
@@ -231,47 +436,74 @@ public class DefaultSyncContextTest exte
         syncCtx.setKeepMissing(true);
         SyncResult result = syncCtx.sync(groupId);
         assertEquals(SyncResult.Status.NOP, result.getStatus());
-        assertNotNull(getUserManager(root).getAuthorizable(groupId));
+        assertNotNull(userManager.getAuthorizable(groupId));
 
         // test sync with 'keepmissing' = false
         syncCtx.setKeepMissing(false);
         result = syncCtx.sync(groupId);
         assertEquals(SyncResult.Status.NOP, result.getStatus());
 
-        assertNotNull(getUserManager(root).getAuthorizable(groupId));
+        assertNotNull(userManager.getAuthorizable(groupId));
     }
 
     @Test
-    public void testSyncByForeignId() throws Exception {
+    public void testSyncByForeignUserId() throws Exception {
         SyncResult result = syncCtx.sync(getTestUser().getID());
+
+        assertEquals(SyncResult.Status.FOREIGN, result.getStatus());
+        SyncedIdentity si = result.getIdentity();
+        assertNotNull(si);
+        assertNull(si.getExternalIdRef());
+        assertFalse(si.isGroup());
+    }
+
+    @Test
+    public void testSyncByForeignGroupId() throws Exception {
+        SyncResult result = syncCtx.sync(createTestGroup().getID());
+
         assertEquals(SyncResult.Status.FOREIGN, result.getStatus());
+        SyncedIdentity si = result.getIdentity();
+        assertNotNull(si);
+        assertNull(si.getExternalIdRef());
+        assertTrue(si.isGroup());
     }
 
     @Test
     public void testSyncByForeignId2() throws Exception {
-        User u = getTestUser();
+        User u = userManager.getAuthorizable(getTestUser().getID(), User.class);
         setExternalID(u, "differentIDP");
 
         SyncResult result = syncCtx.sync(u.getID());
         assertEquals(SyncResult.Status.FOREIGN, result.getStatus());
+        SyncedIdentity si = result.getIdentity();
+        assertNotNull(si);
+        assertEquals(DefaultSyncContext.getIdentityRef(u), si.getExternalIdRef());
+    }
+
+    @Test(expected = SyncException.class)
+    public void testSyncByIdUsingExceptionId() throws Exception {
+        Group gr = userManager.createGroup(TestIdentityProvider.ID_EXCEPTION);
+        setExternalID(gr, idp.getName());
+
+        syncCtx.sync(TestIdentityProvider.ID_EXCEPTION);
     }
 
     @Test
     public void testSyncAutoMembership() throws Exception {
         Group gr = createTestGroup();
 
-        config.user().setAutoMembership(gr.getID());
+        syncConfig.user().setAutoMembership(gr.getID());
 
         SyncResult result = syncCtx.sync(idp.listUsers().next());
         assertEquals(SyncResult.Status.ADD, result.getStatus());
 
-        Authorizable a = getUserManager(root).getAuthorizable(result.getIdentity().getId());
+        Authorizable a = userManager.getAuthorizable(result.getIdentity().getId());
         assertTrue(gr.isDeclaredMember(a));
     }
 
     @Test
     public void testSyncAutoMembershipListsNonExistingGroup() throws Exception {
-        config.user().setAutoMembership("nonExistingGroup");
+        syncConfig.user().setAutoMembership("nonExistingGroup");
 
         SyncResult result = syncCtx.sync(idp.listUsers().next());
         assertEquals(SyncResult.Status.ADD, result.getStatus());
@@ -280,7 +512,7 @@ public class DefaultSyncContextTest exte
     @Test
     public void testSyncAutoMembershipListsUser() throws Exception {
         // set auto-membership config to point to a user instead a group
-        config.user().setAutoMembership(getTestUser().getID());
+        syncConfig.user().setAutoMembership(getTestUser().getID());
         syncCtx.sync(idp.listUsers().next());
     }
 
@@ -295,21 +527,21 @@ public class DefaultSyncContextTest exte
         // sync an external user from the IDP into the repo and make it member
         // of the test group
         SyncResult result = syncCtx.sync(idp.listUsers().next());
-        User user = getUserManager(root).getAuthorizable(result.getIdentity().getId(), User.class);
+        User user = userManager.getAuthorizable(result.getIdentity().getId(), User.class);
         gr.addMember(user);
         root.commit();
 
         // enforce synchronization of the user and it's group membership
         syncCtx.setForceUserSync(true);
-        config.user().setMembershipExpirationTime(-1);
+        syncConfig.user().setMembershipExpirationTime(-1);
 
         // 1. membership nesting is < 0 => membership not synchronized
-        config.user().setMembershipNestingDepth(-1);
+        syncConfig.user().setMembershipNestingDepth(-1);
         syncCtx.sync(user.getID()).getStatus();
         assertTrue(gr.isDeclaredMember(user));
 
         // 2. membership nesting is > 0 => membership gets synchronized
-        config.user().setMembershipNestingDepth(1);
+        syncConfig.user().setMembershipNestingDepth(1);
         assertEquals(SyncResult.Status.UPDATE, syncCtx.sync(user.getID()).getStatus());
 
         assertFalse(gr.isDeclaredMember(user));
@@ -325,14 +557,14 @@ public class DefaultSyncContextTest exte
         // sync an external user from the IDP into the repo and make it member
         // of the test group
         SyncResult result = syncCtx.sync(idp.listUsers().next());
-        User user = getUserManager(root).getAuthorizable(result.getIdentity().getId(), User.class);
+        User user = userManager.getAuthorizable(result.getIdentity().getId(), User.class);
         gr.addMember(user);
         root.commit();
 
         // enforce synchronization of the user and it's group membership
         syncCtx.setForceUserSync(true);
-        config.user().setMembershipExpirationTime(-1);
-        config.user().setMembershipNestingDepth(1);
+        syncConfig.user().setMembershipExpirationTime(-1);
+        syncConfig.user().setMembershipNestingDepth(1);
 
         assertEquals(SyncResult.Status.UPDATE, syncCtx.sync(user.getID()).getStatus());
 
@@ -341,45 +573,640 @@ public class DefaultSyncContextTest exte
         assertTrue(gr.isDeclaredMember(user));
     }
 
-    /**
-     * ExternalIdentity implementation that is neither user nor group.
-     */
-    private final class TestExternalIdentity implements ExternalIdentity {
+    @Test
+    public void testGetAuthorizableUser() throws Exception {
+        ExternalIdentity extUser = idp.listUsers().next();
+        User user = syncCtx.getAuthorizable(extUser, User.class);
+        assertNull(user);
 
-        @Nonnull
-        @Override
-        public ExternalIdentityRef getExternalId() {
-            return new ExternalIdentityRef(getId(), idp.getName());
+        sync(extUser);
+
+        user = syncCtx.getAuthorizable(extUser, User.class);
+        assertNotNull(user);
+    }
+
+    @Test(expected = SyncException.class)
+    public void testGetAuthorizableUserWrongType() throws Exception {
+        ExternalIdentity extUser = idp.listUsers().next();
+        sync(extUser);
+        syncCtx.getAuthorizable(extUser, Group.class);
+    }
+
+    @Test
+    public void testGetAuthorizableGroup() throws Exception {
+        ExternalIdentity extGroup = idp.listGroups().next();
+        Group gr = syncCtx.getAuthorizable(extGroup, Group.class);
+        assertNull(gr);
+
+        sync(extGroup);
+
+        gr = syncCtx.getAuthorizable(extGroup, Group.class);
+        assertNotNull(gr);
+    }
+
+    @Test(expected = SyncException.class)
+    public void testGetAuthorizableGroupWrongType() throws Exception {
+        ExternalIdentity extGroup = idp.listGroups().next();
+        sync(extGroup);
+        syncCtx.getAuthorizable(extGroup, User.class);
+    }
+
+    @Test
+    public void testSyncMembershipDepthNoSync() throws Exception {
+        ExternalUser externalUser = idp.listUsers().next();
+        Authorizable a = syncCtx.createUser(externalUser);
+        root.commit();
+
+        assertTrue(externalUser.getDeclaredGroups().iterator().hasNext());
+
+        syncCtx.syncMembership(externalUser, a, 0);
+        assertFalse(root.hasPendingChanges());
+
+        syncCtx.syncMembership(externalUser, a, -1);
+        assertFalse(root.hasPendingChanges());
+    }
+
+    @Test
+    public void testSyncMembershipDepth1() throws Exception {
+        ExternalUser externalUser = idp.listUsers().next();
+        Authorizable a = syncCtx.createUser(externalUser);
+
+        syncCtx.syncMembership(externalUser, a, 1);
+        assertTrue(root.hasPendingChanges());
+
+        for (ExternalIdentityRef ref : externalUser.getDeclaredGroups()) {
+            Group g = userManager.getAuthorizable(ref.getId(), Group.class);
+            assertNotNull(g);
+            assertTrue(g.isDeclaredMember(a));
         }
+    }
 
-        @Nonnull
-        @Override
-        public String getId() {
-            return "externalId";
+    @Test
+    public void testSyncMembershipDepthInfinite() throws Exception {
+        ExternalUser externalUser = idp.listUsers().next();
+        Authorizable a = syncCtx.createUser(externalUser);
+
+        syncCtx.syncMembership(externalUser, a, Long.MAX_VALUE);
+        assertTrue(root.hasPendingChanges());
+        root.commit();
+
+        for (ExternalIdentityRef ref : externalUser.getDeclaredGroups()) {
+            ExternalIdentity extGr = idp.getIdentity(ref);
+            assertNotNull(extGr);
+
+            for (ExternalIdentityRef inheritedGrRef : extGr.getDeclaredGroups()) {
+                Group g = userManager.getAuthorizable(inheritedGrRef.getId(), Group.class);
+                assertNotNull(g);
+                if (Iterables.contains(externalUser.getDeclaredGroups(), inheritedGrRef)) {
+                    assertTrue(g.isDeclaredMember(a));
+                } else {
+                    assertFalse(g.isDeclaredMember(a));
+                }
+                assertTrue(g.isMember(a));
+            }
         }
+    }
 
-        @Nonnull
-        @Override
-        public String getPrincipalName() {
-            return "principalName";
+    @Test
+    public void testSyncMembershipGroupIsExternalUser() throws Exception {
+        // sync the 'wrong' external group into the repository
+        ExternalIdentity externalIdentity = idp.listUsers().next();
+        sync(externalIdentity);
+
+        // create external user with an synced-ext-user as declared group
+        ExternalUser withWrongDeclaredGroup = new ExternalUserWithDeclaredGroup(externalIdentity.getExternalId());
+
+        try {
+            Authorizable a = syncCtx.createUser(withWrongDeclaredGroup);
+            root.commit();
+
+            syncCtx.syncMembership(withWrongDeclaredGroup, a, 1);
+            assertFalse(root.hasPendingChanges());
+        } finally {
+            Authorizable a = userManager.getAuthorizable(withWrongDeclaredGroup.getId());
+            if (a != null) {
+                a.remove();
+                root.commit();
+            }
         }
+    }
 
-        @CheckForNull
-        @Override
-        public String getIntermediatePath() {
-            return null;
+    @Test
+    public void testSyncMembershipGroupIsSyncedAsUser() throws Exception {
+        ExternalUser fromIDP = idp.listUsers().next();
+        ExternalIdentityRef groupRef = fromIDP.getDeclaredGroups().iterator().next();
+
+        // sync the the ext-user from the idp (but make it just declare a single group)
+        ExternalUser extuser = new ExternalUserWithDeclaredGroup(groupRef, fromIDP);
+        Authorizable a = syncCtx.createUser(extuser);
+
+        // create an external-user based on info that the IDP knows as group and sync it
+        ExternalUser externalIdentity = new ExternalUserFromGroup(idp.getIdentity(groupRef));
+        Authorizable a2 = syncCtx.createUser(externalIdentity);
+        assertFalse(a2.isGroup());
+        root.commit();
+
+        // now sync-ing the membership should not have any effect as the external
+        // group referenced from 'extuser' has already been created in the system
+        // as user.
+        syncCtx.syncMembership(extuser, a, 1);
+        assertFalse(root.hasPendingChanges());
+    }
+
+    @Test
+    public void testApplyMembershipNonExistingGroup() throws Exception {
+        User u = getTestUser();
+
+        assertNull(userManager.getAuthorizable("anyGroup", Group.class));
+        syncCtx.applyMembership(u, ImmutableSet.of("anyGroup"));
+        assertFalse(root.hasPendingChanges());
+    }
+
+    @Test
+    public void testApplyMembershipNonGroup() throws Exception {
+        ExternalUser externalUser = idp.listUsers().next();
+        sync(externalUser);
+        User u = getTestUser();
+
+        syncCtx.applyMembership(userManager.getAuthorizable(externalUser.getId()), ImmutableSet.of(u.getID()));
+        assertFalse(root.hasPendingChanges());
+    }
+
+    @Test
+    public void testApplyMembership() throws Exception {
+        User u = getTestUser();
+        Group gr = createTestGroup();
+
+        syncCtx.applyMembership(u, ImmutableSet.of(gr.getID()));
+        assertTrue(gr.isDeclaredMember(u));
+        assertTrue(root.hasPendingChanges());
+    }
+
+    @Test
+    public void testSyncPropertiesEmptyMap() throws Exception {
+        ExternalUser externalUser = idp.getUser(TestIdentityProvider.ID_SECOND_USER);
+        Authorizable a = syncCtx.createUser(externalUser);
+
+        syncCtx.syncProperties(externalUser, a, ImmutableMap.<String, String>of());
+
+        for (String propName : externalUser.getProperties().keySet()) {
+            assertFalse(a.hasProperty(propName));
+        }
+    }
+
+    @Test
+    public void testSyncPropertiesEmptyMapExistingProps() throws Exception {
+        ExternalUser externalUser = idp.getUser(TestIdentityProvider.ID_SECOND_USER);
+        Authorizable a = syncCtx.createUser(externalUser);
+
+        Value anyValue = valueFactory.createValue("any");
+
+        Map<String, ?> extProps = externalUser.getProperties();
+        for (String propName : extProps.keySet()) {
+            a.setProperty(propName, anyValue);
+        }
+
+        syncCtx.syncProperties(externalUser, a, ImmutableMap.<String, String>of());
+        for (String propName : extProps.keySet()) {
+            assertTrue(a.hasProperty(propName));
+            assertEquals(anyValue, a.getProperty(propName)[0]);
+        }
+    }
+
+    @Test
+    public void testSyncPropertiesMappingRemovesExisting() throws Exception {
+        ExternalUser externalUser = idp.getUser(TestIdentityProvider.ID_SECOND_USER);
+        sync(externalUser);
+
+        Authorizable a = userManager.getAuthorizable(externalUser.getId());
+
+        // create mapping that doesn't match to names in the external-properties
+        // -> previously synced properties must be removed
+        Map<String, String> mapping = new HashMap();
+        Map<String, ?> extProps = externalUser.getProperties();
+        for (String propName : extProps.keySet()) {
+            mapping.put(propName, "any");
+        }
+
+        syncCtx.syncProperties(externalUser, a, mapping);
+        for (String propName : extProps.keySet()) {
+            assertFalse(a.hasProperty(propName));
+        }
+    }
+
+    @Test
+    public void testSyncPropertiesMappingConstants() throws Exception {
+        ExternalUser externalUser = idp.getUser(TestIdentityProvider.ID_SECOND_USER);
+        sync(externalUser);
+
+        Authorizable a = userManager.getAuthorizable(externalUser.getId());
+
+        // create mapping that doesn't match to names in the external-properties
+        // -> previously synced properties must be removed
+        Map<String, String> mapping = new HashMap();
+        Map<String, ?> extProps = externalUser.getProperties();
+        for (String propName : extProps.keySet()) {
+            mapping.put(propName, "\"any\"");
+        }
+
+        syncCtx.syncProperties(externalUser, a, mapping);
+        Value anyValue = valueFactory.createValue("any");
+        for (String propName : extProps.keySet()) {
+            assertTrue(a.hasProperty(propName));
+            assertEquals(anyValue, a.getProperty(propName)[0]);
+        }
+    }
+
+    @Test
+    public void testSyncPropertiesMappingDQuoteName() throws Exception {
+        ExternalUser externalUser = idp.getUser(TestIdentityProvider.ID_SECOND_USER);
+        sync(externalUser);
+
+        Authorizable a = userManager.getAuthorizable(externalUser.getId());
+
+        // mapping to '"' (i.e. name size = 1) which doesn't qualify as constant
+        // -> same behavior expected as with 'testSyncPropertiesMappingRemovesExisting'
+        Map<String, String> mapping = new HashMap();
+        Map<String, ?> extProps = externalUser.getProperties();
+        for (String propName : extProps.keySet()) {
+            mapping.put(propName, "\"");
+        }
+
+        syncCtx.syncProperties(externalUser, a, mapping);
+        for (String propName : extProps.keySet()) {
+            assertFalse(a.hasProperty(propName));
+        }
+    }
+
+    @Test
+    public void testSyncPropertiesMappingNameStartsWithDQuote() throws Exception {
+        ExternalUser externalUser = idp.getUser(TestIdentityProvider.ID_SECOND_USER);
+        sync(externalUser);
+
+        Authorizable a = userManager.getAuthorizable(externalUser.getId());
+
+        // mapping to '"any', which doesn't qualify as constant
+        // -> same behavior expected as with 'testSyncPropertiesMappingRemovesExisting'
+        Map<String, String> mapping = new HashMap();
+        Map<String, ?> extProps = externalUser.getProperties();
+        for (String propName : extProps.keySet()) {
+            mapping.put(propName, "\"any");
+        }
+
+        syncCtx.syncProperties(externalUser, a, mapping);
+        for (String propName : extProps.keySet()) {
+            assertFalse(a.hasProperty(propName));
+        }
+    }
+
+    @Test
+    public void testSyncProperties() throws Exception {
+        ExternalUser externalUser = idp.getUser(TestIdentityProvider.ID_SECOND_USER);
+        Authorizable a = syncCtx.createUser(externalUser);
+
+        // create exact mapping
+        Map<String, String> mapping = new HashMap();
+        Map<String, ?> extProps = externalUser.getProperties();
+        for (String propName : extProps.keySet()) {
+            mapping.put(propName, propName);
+        }
+        syncCtx.syncProperties(externalUser, a, mapping);
+
+        for (String propName : extProps.keySet()) {
+            assertTrue(a.hasProperty(propName));
+
+            Object obj = extProps.get(propName);
+            Value[] vs = a.getProperty(propName);
+            if (vs.length == 1) {
+                assertEquals(syncCtx.createValue(obj), a.getProperty(propName)[0]);
+            } else {
+                Value[] expected = (obj instanceof Collection) ?
+                        syncCtx.createValues((Collection) obj) :
+                        syncCtx.createValues(Arrays.asList((Object[]) obj));
+                assertArrayEquals(expected, a.getProperty(propName));
+            }
+        }
+    }
+
+    @Test
+    public void testSyncPropertiesRemapped() throws Exception {
+        ExternalUser externalUser = idp.getUser(TestIdentityProvider.ID_SECOND_USER);
+        Authorizable a = syncCtx.createUser(externalUser);
+
+        // create exact mapping
+        Map<String, String> mapping = new HashMap();
+        Map<String, ?> extProps = externalUser.getProperties();
+        for (String propName : extProps.keySet()) {
+            mapping.put("a/"+propName, propName);
+        }
+        syncCtx.syncProperties(externalUser, a, mapping);
+
+        for (String propName : extProps.keySet()) {
+            String relPath = "a/" + propName;
+
+            assertTrue(a.hasProperty(relPath));
+
+            Object obj = extProps.get(propName);
+            Value[] vs = a.getProperty(relPath);
+            if (vs.length == 1) {
+                assertEquals(syncCtx.createValue(obj), a.getProperty(relPath)[0]);
+            } else {
+                Value[] expected = (obj instanceof Collection) ?
+                        syncCtx.createValues((Collection) obj) :
+                        syncCtx.createValues(Arrays.asList((Object[]) obj));
+                assertArrayEquals(expected, a.getProperty(relPath));
+            }
+        }
+    }
+
+    @Test
+    public void testIsExpiredLocalGroup() throws Exception {
+        Group gr = createTestGroup();
+        assertTrue(syncCtx.isExpired(gr, syncConfig.group().getExpirationTime(), "any"));
+    }
+
+    @Test
+    public void testIsExpiredEmptyLastSyncedProperty() throws Exception {
+        Group gr = createTestGroup();
+        gr.setProperty(DefaultSyncContext.REP_LAST_SYNCED, new Value[0]);
+
+        assertTrue(syncCtx.isExpired(gr, syncConfig.group().getExpirationTime(), "any"));
+    }
+
+    @Test
+    public void testIsExpiredSyncedUser() throws Exception {
+        ExternalIdentity externalUser = idp.listUsers().next();
+        sync(externalUser);
+
+        Authorizable a = userManager.getAuthorizable(externalUser.getId());
+        assertFalse(syncCtx.isExpired(a, syncConfig.user().getExpirationTime(), "any"));
+        assertTrue(syncCtx.isExpired(a, -1, "any"));
+
+        // create a ctx with a newer 'now'
+        DefaultSyncContext ctx = new DefaultSyncContext(syncConfig, idp, userManager, valueFactory);
+        long expTime = ctx.now - syncCtx.now - 1;
+        assertTrue(ctx.isExpired(a, expTime, "any"));
+
+        // remove last-sync property
+        a.removeProperty(DefaultSyncContext.REP_LAST_SYNCED);
+        assertTrue(syncCtx.isExpired(a, syncConfig.user().getExpirationTime(), "any"));
+    }
+
+    @Test
+    public void testIsExpiredSyncedGroup() throws Exception {
+        ExternalIdentity externalGroup = idp.listGroups().next();
+        sync(externalGroup);
+
+        Authorizable a = userManager.getAuthorizable(externalGroup.getId());
+        assertFalse(syncCtx.isExpired(a, syncConfig.group().getExpirationTime(), "any"));
+        assertTrue(syncCtx.isExpired(a, -1, "any"));
+
+        // create a ctx with a newer 'now'
+        DefaultSyncContext ctx = new DefaultSyncContext(syncConfig, idp, userManager, valueFactory);
+        long expTime = ctx.now - syncCtx.now - 1;
+        assertTrue(ctx.isExpired(a, expTime, "any"));
+
+        // remove last-sync property
+        a.removeProperty(DefaultSyncContext.REP_LAST_SYNCED);
+        assertTrue(syncCtx.isExpired(a, syncConfig.group().getExpirationTime(), "any"));
+    }
+
+    @Test
+    public void testCreateValueNull() throws Exception {
+        assertNull(syncCtx.createValue(null));
+    }
+
+    @Test
+    public void testCreateValueString() throws Exception {
+        Value v = syncCtx.createValue("s");
+        assertNotNull(v);
+        assertEquals(PropertyType.STRING, v.getType());
+        assertEquals("s", v.getString());
+
+        v = syncCtx.createValue(new char[] {'s'});
+        assertNotNull(v);
+        assertEquals(PropertyType.STRING, v.getType());
+        assertEquals("s", v.getString());
+
+        Object o = new TestIdentityProvider.ForeignExternalUser();
+        v = syncCtx.createValue(o);
+        assertNotNull(v);
+        assertEquals(PropertyType.STRING, v.getType());
+        assertEquals(o.toString(), v.getString());
+    }
+
+    @Test
+    public void testCreateValueBoolean() throws Exception {
+        Value v = syncCtx.createValue(true);
+        assertNotNull(v);
+        assertEquals(PropertyType.BOOLEAN, v.getType());
+        assertEquals(true, v.getBoolean());
+    }
+
+    @Test
+    public void testCreateValueLong() throws Exception {
+        Value v = syncCtx.createValue(Long.MAX_VALUE);
+        assertNotNull(v);
+        assertEquals(PropertyType.LONG, v.getType());
+        assertEquals(Long.MAX_VALUE, v.getLong());
+
+        v = syncCtx.createValue(Integer.valueOf(23));
+        assertNotNull(v);
+        assertEquals(PropertyType.LONG, v.getType());
+        assertEquals(23, v.getLong());
+
+        v = syncCtx.createValue(Short.MIN_VALUE);
+        assertNotNull(v);
+        assertEquals(PropertyType.LONG, v.getType());
+        assertEquals(Short.MIN_VALUE, v.getLong());
+
+        v = syncCtx.createValue(Byte.MAX_VALUE);
+        assertNotNull(v);
+        assertEquals(PropertyType.LONG, v.getType());
+        assertEquals(Byte.MAX_VALUE, v.getLong());
+    }
+
+    @Test
+    public void testCreateValueDouble() throws Exception {
+        Value v = syncCtx.createValue(Double.valueOf(1.1));
+        assertNotNull(v);
+        assertEquals(PropertyType.DOUBLE, v.getType());
+        assertEquals(1.1, v.getDouble(), 0);
+
+        v = syncCtx.createValue(Float.NaN);
+        assertNotNull(v);
+        assertEquals(PropertyType.DOUBLE, v.getType());
+        assertEquals(Float.NaN, v.getDouble(), 0);
+    }
+
+    @Test
+    public void testCreateValueDate() throws Exception {
+        Date d = new Date();
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(d);
+
+        Value v = syncCtx.createValue(cal);
+        assertNotNull(v);
+        assertEquals(PropertyType.DATE, v.getType());
+
+        Value v2 = syncCtx.createValue(d);
+        assertNotNull(v2);
+        assertEquals(PropertyType.DATE, v2.getType());
+
+        assertEquals(v, v2);
+    }
+
+    @Test
+    public void testCreateValueDecimal() throws Exception {
+        BigDecimal dec = new BigDecimal(123);
+        Value v = syncCtx.createValue(dec);
+        assertNotNull(v);
+        assertEquals(PropertyType.DECIMAL, v.getType());
+        assertEquals(dec, v.getDecimal());
+    }
+
+    @Test
+    public void testCreateValueFromBytesArray() throws Exception {
+        byte[] bytes = new byte[]{'a', 'b'};
+        ByteArrayInputStream is = new ByteArrayInputStream(bytes);
+        Binary binary = valueFactory.createBinary(is);
+
+        Value v = syncCtx.createValue(bytes);
+        assertNotNull(v);
+        assertEquals(PropertyType.BINARY, v.getType());
+        assertEquals(binary, v.getBinary());
+    }
+
+    /**
+     * @see <a href="https://issues.apache.org/jira/browse/OAK-4231">OAK-4231</a>
+     */
+    @Test
+    public void testCreateValueFromBinary() throws Exception {
+        byte[] bytes = new byte[]{'a', 'b'};
+        ByteArrayInputStream is = new ByteArrayInputStream(bytes);
+        Binary binary = valueFactory.createBinary(is);
+
+        Value v = syncCtx.createValue(binary);
+        assertNotNull(v);
+        assertEquals(PropertyType.BINARY, v.getType());
+        assertEquals(binary, v.getBinary());
+    }
+
+    /**
+     * @see <a href="https://issues.apache.org/jira/browse/OAK-4231">OAK-4231</a>
+     */
+    @Test
+    public void testCreateValueFromInputStream() throws Exception {
+        byte[] bytes = new byte[]{'a', 'b'};
+        ByteArrayInputStream is = new ByteArrayInputStream(bytes);
+        Binary binary = valueFactory.createBinary(is);
+
+        Value v = syncCtx.createValue(is);
+        assertNotNull(v);
+        assertEquals(PropertyType.BINARY, v.getType());
+        assertEquals(binary, v.getBinary());
+    }
+
+    @Test
+    public void testCreateValuesEmptyCollection() throws Exception {
+        Value[] vs = syncCtx.createValues(ImmutableList.of());
+        assertNotNull(vs);
+        assertEquals(0, vs.length);
+    }
+
+    @Test
+    public void testCreateValuesSkipsNull() throws Exception {
+        List<String> strings = Lists.newArrayList("s", null, null, "t");
+        Value[] vs = syncCtx.createValues(strings);
+        assertNotNull(vs);
+        assertEquals(2, vs.length);
+    }
+
+    @Test
+    public void testIsSameIDPNull() throws Exception {
+        assertFalse(syncCtx.isSameIDP((Authorizable) null));
+    }
+
+    @Test
+    public void testIsSameIDPLocalGroup() throws Exception {
+        assertFalse(syncCtx.isSameIDP(createTestGroup()));
+    }
+
+    @Test
+    public void testIsSameIDPLocalUser() throws Exception {
+        assertFalse(syncCtx.isSameIDP(getTestUser()));
+    }
+
+    @Test
+    public void testIsSameIDPSyncedGroup() throws Exception {
+        ExternalIdentity externalGroup = idp.listGroups().next();
+        sync(externalGroup);
+
+        assertTrue(syncCtx.isSameIDP(userManager.getAuthorizable(externalGroup.getId())));
+    }
+
+    @Test
+    public void testIsSameIDPSyncedUser() throws Exception {
+        ExternalIdentity externalUser = idp.listUsers().next();
+        sync(externalUser);
+
+        assertTrue(syncCtx.isSameIDP(userManager.getAuthorizable(externalUser.getId())));
+    }
+
+    @Test
+    public void testIsSameIDPMissingExternalId() throws Exception {
+        ExternalIdentity externalUser = idp.listUsers().next();
+        sync(externalUser);
+
+        Authorizable a = userManager.getAuthorizable(externalUser.getId());
+        a.removeProperty(DefaultSyncContext.REP_EXTERNAL_ID);
+
+        assertFalse(syncCtx.isSameIDP(a));
+    }
+
+    @Test
+    public void testIsSameIDPForeign() throws Exception {
+        Group gr = createTestGroup();
+        setExternalID(gr, "some_other_idp");
+
+        assertFalse(syncCtx.isSameIDP(gr));
+    }
+
+    @Test
+    public void testIsSameIDPExternalIdentityRef() throws Exception {
+        assertFalse(syncCtx.isSameIDP(new TestIdentityProvider.ForeignExternalUser().getExternalId()));
+        assertFalse(syncCtx.isSameIDP(new TestIdentityProvider.ForeignExternalGroup().getExternalId()));
+
+        assertTrue(syncCtx.isSameIDP(new TestIdentityProvider.TestIdentity().getExternalId()));
+        assertTrue(syncCtx.isSameIDP(idp.listGroups().next().getExternalId()));
+        assertTrue(syncCtx.isSameIDP(idp.listUsers().next().getExternalId()));
+    }
+
+    private final class ExternalUserWithDeclaredGroup extends TestIdentityProvider.TestIdentity implements ExternalUser {
+
+        private final ExternalIdentityRef declaredGroupRef;
+
+        private ExternalUserWithDeclaredGroup(@Nonnull ExternalIdentityRef declaredGroupRef) {
+            super("externalId");
+            this.declaredGroupRef = declaredGroupRef;
+        }
+
+        private ExternalUserWithDeclaredGroup(@Nonnull ExternalIdentityRef declaredGroupRef, @Nonnull ExternalIdentity base) {
+            super(base);
+            this.declaredGroupRef = declaredGroupRef;
         }
 
         @Nonnull
         @Override
         public Iterable<ExternalIdentityRef> getDeclaredGroups() {
-            return ImmutableSet.of();
+            return ImmutableSet.of(declaredGroupRef);
         }
+    }
 
-        @Nonnull
-        @Override
-        public Map<String, ?> getProperties() {
-            return ImmutableMap.of();
+    private final class ExternalUserFromGroup extends TestIdentityProvider.TestIdentity implements ExternalUser {
+
+        private ExternalUserFromGroup(@Nonnull ExternalIdentity base) {
+            super(base);
         }
     }
 }
\ No newline at end of file

Copied: jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/CustomCredentialsSupportTest.java (from r1735141, jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/CustomCredentialsSupportTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/CustomCredentialsSupportTest.java?p2=jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/CustomCredentialsSupportTest.java&p1=jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/CustomCredentialsSupportTest.java&r1=1735141&r2=1756777&rev=1756777&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/CustomCredentialsSupportTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/CustomCredentialsSupportTest.java Thu Aug 18 13:15:22 2016
@@ -52,8 +52,6 @@ import static org.junit.Assert.fail;
  */
 public class CustomCredentialsSupportTest extends ExternalLoginModuleTestBase {
 
-    private final IDP idp = new IDP();
-
     private static void assertAttributes(@Nonnull Map<String, ?> expected, @Nonnull AuthInfo info) {
         assertEquals(expected.size(), info.getAttributeNames().length);
         for (String aName : info.getAttributeNames()) {
@@ -69,7 +67,7 @@ public class CustomCredentialsSupportTes
         try {
             AuthInfo info = cs.getAuthInfo();
             assertEquals("testUser", info.getUserID());
-            assertAttributes(idp.getAttributes(creds), info);
+            assertAttributes(((IDP) idp).getAttributes(creds), info);
         } finally {
             cs.close();
         }
@@ -93,12 +91,7 @@ public class CustomCredentialsSupportTes
 
     @Override
     protected ExternalIdentityProvider createIDP() {
-        return idp;
-    }
-
-    @Override
-    protected void destroyIDP(ExternalIdentityProvider idp) {
-        // ignore
+        return new IDP();
     }
 
     private static final class TestCredentials implements Credentials {
@@ -138,7 +131,7 @@ public class CustomCredentialsSupportTes
                     @Nonnull
                     @Override
                     public ExternalIdentityRef getExternalId() {
-                        return new ExternalIdentityRef(uid, "test");
+                        return new ExternalIdentityRef(uid, getName());
                     }
 
                     @Nonnull

Copied: jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java (from r1739712, jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java?p2=jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java&p1=jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java&r1=1739712&r2=1756777&rev=1756777&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java Thu Aug 18 13:15:22 2016
@@ -56,8 +56,6 @@ import static org.junit.Assert.assertTru
  */
 public class DefaultSyncHandlerTest extends ExternalLoginModuleTestBase {
 
-    private String userId = TestIdentityProvider.ID_TEST_USER;
-
     private UserManager userManager;
     private DefaultSyncHandler syncHandler;
 
@@ -77,15 +75,6 @@ public class DefaultSyncHandlerTest exte
         super.after();
     }
 
-    protected ExternalIdentityProvider createIDP() {
-        return new TestIdentityProvider();
-    }
-
-    @Override
-    protected void destroyIDP(ExternalIdentityProvider idp) {
-    // ignore
-    }
-
     @Override
     protected void setSyncConfig(DefaultSyncConfig cfg) {
         if (cfg != null) {
@@ -129,13 +118,13 @@ public class DefaultSyncHandlerTest exte
 
     @Test
     public void testFindExternalIdentity() throws Exception {
-        login(new SimpleCredentials(userId, new char[0])).close();
+        login(new SimpleCredentials(USER_ID, new char[0])).close();
         root.refresh();
 
-        SyncedIdentity id = syncHandler.findIdentity(userManager, userId);
+        SyncedIdentity id = syncHandler.findIdentity(userManager, USER_ID);
         assertNotNull("known authorizable should exist", id);
         assertEquals("external user should have correct external ref.idp", idp.getName(), id.getExternalIdRef().getProviderName());
-        assertEquals("external user should have correct external ref.id", userId, id.getExternalIdRef().getId());
+        assertEquals("external user should have correct external ref.id", USER_ID, id.getExternalIdRef().getId());
     }
 
     @Test
@@ -153,23 +142,23 @@ public class DefaultSyncHandlerTest exte
 
     @Test
     public void testFindIdentityWithRemovedExternalId() throws Exception {
-        sync(userId, false);
+        sync(USER_ID, false);
 
         // NOTE: this is only possible as long the rep:externalId property is not protected
-        Authorizable authorizable = userManager.getAuthorizable(userId);
+        Authorizable authorizable = userManager.getAuthorizable(USER_ID);
         authorizable.removeProperty(DefaultSyncContext.REP_EXTERNAL_ID);
         root.commit();
 
-        SyncedIdentity si = syncHandler.findIdentity(userManager, userId);
+        SyncedIdentity si = syncHandler.findIdentity(userManager, USER_ID);
         assertNull(si.getExternalIdRef());
     }
 
     @Test
     public void testRequiresSyncAfterCreate() throws Exception {
-        login(new SimpleCredentials(userId, new char[0])).close();
+        login(new SimpleCredentials(USER_ID, new char[0])).close();
         root.refresh();
 
-        SyncedIdentity id = syncHandler.findIdentity(userManager, userId);
+        SyncedIdentity id = syncHandler.findIdentity(userManager, USER_ID);
         assertNotNull("Known authorizable should exist", id);
 
         assertFalse("Freshly synced id should not require sync", syncHandler.requiresSync(id));
@@ -177,18 +166,18 @@ public class DefaultSyncHandlerTest exte
 
     @Test
     public void testRequiresSyncExpiredSyncProperty() throws Exception {
-        login(new SimpleCredentials(userId, new char[0])).close();
+        login(new SimpleCredentials(USER_ID, new char[0])).close();
         root.refresh();
 
         final Calendar nowCal = Calendar.getInstance();
         nowCal.setTimeInMillis(nowCal.getTimeInMillis() - 1000);
         Value nowValue = getValueFactory().createValue(nowCal);
 
-        Authorizable a = userManager.getAuthorizable(userId);
+        Authorizable a = userManager.getAuthorizable(USER_ID);
         a.setProperty(DefaultSyncContext.REP_LAST_SYNCED, nowValue);
         root.commit();
 
-        SyncedIdentity id = syncHandler.findIdentity(userManager, userId);
+        SyncedIdentity id = syncHandler.findIdentity(userManager, USER_ID);
         assertNotNull("known authorizable should exist", id);
 
         assertTrue("synced id should require sync", syncHandler.requiresSync(id));
@@ -196,25 +185,25 @@ public class DefaultSyncHandlerTest exte
 
     @Test
     public void testRequiresSyncMissingSyncProperty() throws Exception {
-        sync(userId, false);
+        sync(USER_ID, false);
 
-        Authorizable a = userManager.getAuthorizable(userId);
+        Authorizable a = userManager.getAuthorizable(USER_ID);
         a.removeProperty(DefaultSyncContext.REP_LAST_SYNCED);
         root.commit();
 
-        SyncedIdentity si = syncHandler.findIdentity(userManager, userId);
+        SyncedIdentity si = syncHandler.findIdentity(userManager, USER_ID);
         assertNotNull(si);
         assertTrue(syncHandler.requiresSync(si));
     }
 
     @Test
     public void testRequiresSyncMissingExternalIDRef() throws Exception {
-        assertTrue(syncHandler.requiresSync(new DefaultSyncedIdentity(userId, null, false, Long.MAX_VALUE)));
+        assertTrue(syncHandler.requiresSync(new DefaultSyncedIdentity(USER_ID, null, false, Long.MAX_VALUE)));
     }
 
     @Test
     public void testRequiresSyncNotYetSynced() throws Exception {
-        assertTrue(syncHandler.requiresSync(new DefaultSyncedIdentity(userId, idp.getUser(userId).getExternalId(), false, Long.MIN_VALUE)));
+        assertTrue(syncHandler.requiresSync(new DefaultSyncedIdentity(USER_ID, idp.getUser(USER_ID).getExternalId(), false, Long.MIN_VALUE)));
     }
 
     @Test
@@ -238,11 +227,11 @@ public class DefaultSyncHandlerTest exte
 
     @Test
     public void testListIdentitiesAfterSync() throws Exception {
-        sync(userId, false);
+        sync(USER_ID, false);
 
-        // membership-nesting is 1 => expect only 'userId' plus the declared group-membership
-        Set<String> expected = Sets.newHashSet(userId);
-        for (ExternalIdentityRef extRef : idp.getUser(userId).getDeclaredGroups()) {
+        // membership-nesting is 1 => expect only 'USER_ID' plus the declared group-membership
+        Set<String> expected = Sets.newHashSet(USER_ID);
+        for (ExternalIdentityRef extRef : idp.getUser(USER_ID).getDeclaredGroups()) {
             expected.add(extRef.getId());
         }
 

Copied: jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DynamicSyncContextTest.java (from r1744292, jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DynamicSyncContextTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DynamicSyncContextTest.java?p2=jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DynamicSyncContextTest.java&p1=jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DynamicSyncContextTest.java&r1=1744292&r2=1756777&rev=1756777&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DynamicSyncContextTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DynamicSyncContextTest.java Thu Aug 18 13:15:22 2016
@@ -115,7 +115,7 @@ public class DynamicSyncContextTest exte
             };
         });
 
-        Set<String> expected = new HashSet<>();
+        Set<String> expected = new HashSet<String>();
         collectGroupPrincipals(expected, externalIdentity.getDeclaredGroups(), depth);
 
         assertEquals(expected, ImmutableSet.copyOf(pNames));

Modified: jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityImporterTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityImporterTest.java?rev=1756777&r1=1744292&r2=1756777&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityImporterTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityImporterTest.java Thu Aug 18 13:15:22 2016
@@ -50,6 +50,16 @@ import static org.junit.Assert.assertTru
  */
 public class ExternalIdentityImporterTest {
 
+    public static final String XML_EXTERNAL_USER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+            "<sv:node sv:name=\"t\" xmlns:mix=\"http://www.jcp.org/jcr/mix/1.0\" xmlns:nt=\"http://www.jcp.org/jcr/nt/1.0\" xmlns:fn_old=\"http://www.w3.org/2004/10/xpath-functions\" xmlns:fn=\"http://www.w3.org/2005/xpath-functions\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:sv=\"http://www.jcp.org/jcr/sv/1.0\" xmlns:rep=\"internal\" xmlns:jcr=\"http://www.jcp.org/jcr/1.0\">" +
+            "   <sv:property sv:name=\"jcr:primaryType\" sv:type=\"Name\"><sv:value>rep:User</sv:value></sv:property>" +
+            "   <sv:property sv:name=\"jcr:uuid\" sv:type=\"String\"><sv:value>e358efa4-89f5-3062-b10d-d7316b65649e</sv:value></sv:property>" +
+            "   <sv:property sv:name=\"rep:authorizableId\" sv:type=\"String\"><sv:value>t</sv:value></sv:property>" +
+            "   <sv:property sv:name=\"rep:principalName\" sv:type=\"String\"><sv:value>tPrinc</sv:value></sv:property>" +
+            "   <sv:property sv:name=\"rep:externalId\" sv:type=\"String\"><sv:value>idp;ext-t</sv:value></sv:property>" +
+            "   <sv:property sv:name=\"rep:lastSynced\" sv:type=\"Date\"><sv:value>2016-05-03T10:03:08.061+02:00</sv:value></sv:property>" +
+            "</sv:node>";
+
     public static final String XML_EXTERNAL_USER_WITH_PRINCIPAL_NAMES = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
             "<sv:node sv:name=\"t\" xmlns:mix=\"http://www.jcp.org/jcr/mix/1.0\" xmlns:nt=\"http://www.jcp.org/jcr/nt/1.0\" xmlns:fn_old=\"http://www.w3.org/2004/10/xpath-functions\" xmlns:fn=\"http://www.w3.org/2005/xpath-functions\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:sv=\"http://www.jcp.org/jcr/sv/1.0\" xmlns:rep=\"internal\" xmlns:jcr=\"http://www.jcp.org/jcr/1.0\">" +
             "   <sv:property sv:name=\"jcr:primaryType\" sv:type=\"Name\"><sv:value>rep:User</sv:value></sv:property>" +
@@ -67,7 +77,7 @@ public class ExternalIdentityImporterTes
 
     @Before
     public void before() throws Exception {
-        securityProvider = new TestSecurityProvider(getConfigurationParameters());
+        securityProvider = new TestSecurityProvider(getConfigurationParameters(), new ExternalPrincipalConfiguration());
         Jcr jcr = new Jcr();
         jcr.with(securityProvider);
         repo = jcr.createRepository();
@@ -133,6 +143,20 @@ public class ExternalIdentityImporterTes
     }
 
     @Test
+    public void importExternalUser() throws Exception {
+        Node parent = doImport(createSession(false), UserConstants.DEFAULT_USER_PATH, XML_EXTERNAL_USER);
+        assertHasProperties(parent.getNode("t"), ExternalIdentityConstants.REP_EXTERNAL_ID, ExternalIdentityConstants.REP_LAST_SYNCED);
+        assertNotHasProperties(parent.getNode("t"), ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES);
+    }
+
+    @Test
+    public void importExternalUserAsSystem() throws Exception {
+        Node parent = doImport(createSession(true), UserConstants.DEFAULT_USER_PATH, XML_EXTERNAL_USER);
+        assertHasProperties(parent.getNode("t"), ExternalIdentityConstants.REP_EXTERNAL_ID, ExternalIdentityConstants.REP_LAST_SYNCED);
+        assertNotHasProperties(parent.getNode("t"), ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES);
+    }
+
+    @Test
     public void importExternalUserWithPrincipalNames() throws Exception {
         Node parent = doImport(createSession(false), UserConstants.DEFAULT_USER_PATH, XML_EXTERNAL_USER_WITH_PRINCIPAL_NAMES);
         assertHasProperties(parent.getNode("t"), ExternalIdentityConstants.REP_EXTERNAL_ID);

Modified: jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfigurationTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfigurationTest.java?rev=1756777&r1=1744292&r2=1756777&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfigurationTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfigurationTest.java Thu Aug 18 13:15:22 2016
@@ -34,7 +34,6 @@ import org.apache.jackrabbit.oak.namepat
 import org.apache.jackrabbit.oak.spi.commit.MoveTracker;
 import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
 import org.apache.jackrabbit.oak.spi.lifecycle.WorkspaceInitializer;
-import org.apache.jackrabbit.oak.spi.security.Context;
 import org.apache.jackrabbit.oak.spi.security.authentication.external.AbstractExternalAuthTest;
 import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityProvider;
 import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncContext;
@@ -121,14 +120,6 @@ public class ExternalPrincipalConfigurat
     }
 
     @Test
-    public void testGetContext() {
-        assertSame(Context.DEFAULT, principalConfiguration.getContext());
-
-        enable();
-        assertSame(Context.DEFAULT, principalConfiguration.getContext());
-    }
-
-    @Test
     public void testGetWorkspaceInitializer() {
         assertSame(WorkspaceInitializer.DEFAULT, principalConfiguration.getWorkspaceInitializer());
 

Modified: jackrabbit/oak/branches/1.2/oak-auth-ldap/src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-auth-ldap/src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-auth-ldap/src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java (original)
+++ jackrabbit/oak/branches/1.2/oak-auth-ldap/src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java Thu Aug 18 13:15:22 2016
@@ -162,7 +162,7 @@ public abstract class LdapLoginTestBase
     }
 
     @Override
-    protected void destroyIDP(ExternalIdentityProvider idp) {
+    protected void destroyIDP() {
         ((LdapIdentityProvider) idp).close();
     }