diff --git a/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java b/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java index 55f7f84314..7faf4dab3b 100755 --- a/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java +++ b/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java @@ -16,16 +16,20 @@ */ package org.apache.jackrabbit.oak.upgrade; +import java.io.File; +import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Properties; import java.util.Set; import javax.jcr.RepositoryException; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import org.apache.commons.lang.StringUtils; @@ -40,6 +44,7 @@ import org.apache.jackrabbit.oak.plugins.migration.NodeStateCopier; import org.apache.jackrabbit.oak.plugins.migration.report.LoggingReporter; import org.apache.jackrabbit.oak.plugins.migration.report.ReportingNodeState; import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate; +import org.apache.jackrabbit.oak.security.internal.SecurityProviderBuilder; import org.apache.jackrabbit.oak.segment.SegmentNodeState; import org.apache.jackrabbit.oak.segment.file.FileStore; import org.apache.jackrabbit.oak.spi.commit.CommitHook; @@ -47,6 +52,11 @@ import org.apache.jackrabbit.oak.spi.commit.CommitInfo; import org.apache.jackrabbit.oak.spi.commit.CompositeEditorProvider; import org.apache.jackrabbit.oak.spi.commit.EditorHook; import org.apache.jackrabbit.oak.spi.commit.EmptyHook; +import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; +import org.apache.jackrabbit.oak.spi.security.SecurityConfiguration; +import org.apache.jackrabbit.oak.spi.security.SecurityProvider; +import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration; +import org.apache.jackrabbit.oak.spi.security.user.UserConstants; import org.apache.jackrabbit.oak.spi.state.ApplyDiff; import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry; import org.apache.jackrabbit.oak.spi.state.NodeBuilder; @@ -88,6 +98,8 @@ public class RepositorySidegrade { static final int LOG_NODE_COPY = Integer.getInteger("oak.upgrade.logNodeCopy", 10000); + static final String SECURITY_USER_CONFIG_FILE = System.getProperty("oak.upgrade.security.user.config"); + private static final String WORKSPACE_NAME_PROP = "oak.upgrade.workspaceName"; /** @@ -407,6 +419,8 @@ public class RepositorySidegrade { private void migrateWithoutCheckpoints() throws CommitFailedException, RepositoryException { final List hooks = new ArrayList<>(); + final String workspaceName = getWorkspaceName(); + if (customCommitHooks != null) { hooks.addAll(customCommitHooks); } @@ -423,8 +437,15 @@ public class RepositorySidegrade { if (!versionCopyConfiguration.skipOrphanedVersionsCopy()) { copyVersionStorage(targetRoot, getVersionStorage(sourceRoot), versionStorage, versionCopyConfiguration); } - hooks.add(new EditorHook(new VersionableEditor.Provider(sourceRoot, getWorkspaceName(), versionCopyConfiguration))); + hooks.add(new EditorHook(new VersionableEditor.Provider(sourceRoot, workspaceName, versionCopyConfiguration))); + } + + SecurityProvider security = getSecurityProvider(); + + for (SecurityConfiguration securityConfig : security.getConfigurations()) { + hooks.addAll(securityConfig.getCommitHooks(workspaceName)); } + // type validation, reference and indexing hooks hooks.add(new EditorHook(new CompositeEditorProvider( createTypeEditorProvider(), @@ -541,4 +562,44 @@ public class RepositorySidegrade { return target.getRoot().getChildNodeEntries().iterator().hasNext(); } + public static SecurityProvider getSecurityProvider() { + ConfigurationParameters configParams; + if (SECURITY_USER_CONFIG_FILE == null) { + configParams = createDefaultSecurityConfig(); + } else { + configParams = loadSecurityConfig(SECURITY_USER_CONFIG_FILE); + } + return SecurityProviderBuilder.newBuilder().with(configParams).build(); + } + + private static ConfigurationParameters loadSecurityConfig(String securityUserConfigFile) { + try (FileReader reader = new FileReader(new File(securityUserConfigFile))) { + Properties properties = new Properties(); + properties.load(reader); + ConfigurationParameters userConfig = ConfigurationParameters.of(properties); + return ConfigurationParameters.of(ImmutableMap.of( + UserConfiguration.NAME, + ConfigurationParameters.of(userConfig))); + } catch (IOException e) { + LOG.error("Can't read the security properties", e); + return createDefaultSecurityConfig(); + } + } + + private static ConfigurationParameters createDefaultSecurityConfig() { + Map userConfigMap = ImmutableMap.of( + UserConstants.PARAM_ADMIN_ID,"admin", + UserConstants.PARAM_ANONYMOUS_ID, "anonymous", + UserConstants.PARAM_USER_PATH, "/home/users", + UserConstants.PARAM_GROUP_PATH, "/home/groups", + UserConstants.PARAM_DEFAULT_DEPTH, "1" + ); + + ConfigurationParameters userConfig = ConfigurationParameters.of(userConfigMap); + return ConfigurationParameters.of(ImmutableMap.of( + UserConfiguration.NAME, + ConfigurationParameters.of(userConfig))); + } + + } diff --git a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeSidegradeTest.java b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeSidegradeTest.java index 0b977e2bc1..d55d89446c 100644 --- a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeSidegradeTest.java +++ b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeExcludeSidegradeTest.java @@ -16,75 +16,206 @@ */ package org.apache.jackrabbit.oak.upgrade; -import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder; - -import java.io.File; -import java.io.IOException; - +import javax.jcr.Credentials; import javax.jcr.RepositoryException; import javax.jcr.Session; +import javax.jcr.SimpleCredentials; +import org.apache.jackrabbit.JcrConstants; +import org.apache.jackrabbit.api.JackrabbitSession; +import org.apache.jackrabbit.api.security.user.UserManager; +import org.apache.jackrabbit.commons.JcrUtils; +import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils; import org.apache.jackrabbit.oak.Oak; import org.apache.jackrabbit.oak.jcr.Jcr; import org.apache.jackrabbit.oak.jcr.repository.RepositoryImpl; -import org.apache.jackrabbit.oak.segment.SegmentNodeStore; -import org.apache.jackrabbit.oak.segment.SegmentNodeStoreBuilders; -import org.apache.jackrabbit.oak.segment.file.FileStore; -import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException; +import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore; import org.apache.jackrabbit.oak.spi.state.NodeStore; import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class IncludeExcludeSidegradeTest { + + public static final Credentials CREDENTIALS = new SimpleCredentials("admin", "admin".toCharArray()); + + private NodeStore sourceNodeStore; -public class IncludeExcludeSidegradeTest extends IncludeExcludeUpgradeTest { + private NodeStore targetNodeStore; + + private RepositoryImpl targetRepository; + + private Session targetSession; @Before - public synchronized void upgradeRepository() throws Exception { - if (targetNodeStore == null) { - File directory = getTestDirectory(); - File source = new File(directory, "source"); - source.mkdirs(); - FileStore fileStore = fileStoreBuilder(source).build(); - SegmentNodeStore segmentNodeStore = SegmentNodeStoreBuilders.builder(fileStore).build(); - RepositoryImpl repository = (RepositoryImpl) new Jcr(new Oak(segmentNodeStore)).createRepository(); - Session session = repository.login(CREDENTIALS); - try { - createSourceContent(session); - } finally { - session.save(); - session.logout(); - repository.shutdown(); - fileStore.close(); - } - final NodeStore target = getTargetNodeStore(); - doUpgradeRepository(source, target); - targetNodeStore = target; - } + public void prepareNodeStores() throws RepositoryException { + sourceNodeStore = new MemoryNodeStore(); + withSession(sourceNodeStore, s -> { + createCommonContent(s); + createSourceContent(s); + }); + + targetNodeStore = new MemoryNodeStore(); + withSession(targetNodeStore, s -> { + createCommonContent(s); + }); + + performSidegrade(); + + targetRepository = getRepository(targetNodeStore); + targetSession = targetRepository.login(CREDENTIALS); } - @Override - protected void doUpgradeRepository(File source, NodeStore target) throws RepositoryException, IOException { - FileStore fileStore; - try { - fileStore = fileStoreBuilder(source).build(); - } catch (InvalidFileStoreVersionException e) { - throw new IllegalStateException(e); + public void cleanup() { + targetRepository.shutdown(); + } + + @Test + public void shouldHaveIncludedPaths() throws RepositoryException { + assertExists( + "/content/foo/en", + "/content/assets/foo/2015/02", + "/content/assets/foo/2015/01", + "/content/assets/foo/2014" + ); + } + + @Test + public void shouldLackPathsThatWereNotIncluded() throws RepositoryException { + assertMissing( + "/content/foo/de", + "/content/foo/fr", + "/content/foo/it" + ); + } + + @Test + public void shouldLackExcludedPaths() throws RepositoryException { + assertMissing( + "/content/assets/foo/2013", + "/content/assets/foo/2012", + "/content/assets/foo/2011", + "/content/assets/foo/2010" + ); + } + + @Test + public void testPermissions() throws RepositoryException { + Session aliceSession = targetRepository.login(new SimpleCredentials("alice", "bar".toCharArray())); + Session bobSession = targetRepository.login(new SimpleCredentials("bob", "bar".toCharArray())); + + assertExists(aliceSession, + "/content/assets/foo/2015/02", + "/content/assets/foo/2015/01", + "/content/assets/foo/2014" + ); + + assertMissing(aliceSession, + "/content/foo/en" + ); + + assertExists(bobSession, + "/content/foo/en" + ); + + assertMissing(bobSession, + "/content/assets/foo/2015/02", + "/content/assets/foo/2015/01", + "/content/assets/foo/2014" + ); + } + + private void createCommonContent(JackrabbitSession session) throws RepositoryException { + UserManager um = session.getUserManager(); + um.createUser("alice", "bar"); + um.createUser("bob", "bar"); + session.save(); + } + + private void createSourceContent(JackrabbitSession session) throws RepositoryException { + for (String p : Arrays.asList( + "/content/foo/de", + "/content/foo/en", + "/content/foo/fr", + "/content/foo/it", + "/content/assets/foo", + "/content/assets/foo/2015", + "/content/assets/foo/2015/02", + "/content/assets/foo/2015/01", + "/content/assets/foo/2014", + "/content/assets/foo/2013", + "/content/assets/foo/2012", + "/content/assets/foo/2011", + "/content/assets/foo/2010/12")) { + JcrUtils.getOrCreateByPath(p, JcrConstants.NT_FOLDER, JcrConstants.NT_FOLDER, session, false); } - SegmentNodeStore segmentNodeStore = SegmentNodeStoreBuilders.builder(fileStore).build(); + + AccessControlUtils.denyAllToEveryone(session, "/content/foo/en"); + AccessControlUtils.allow(session.getNode("/content/foo/en"), "bob", "jcr:read"); + + AccessControlUtils.denyAllToEveryone(session,"/content/assets/foo"); + AccessControlUtils.allow(session.getNode("/content/assets/foo"), "alice", "jcr:read"); + } + + private void performSidegrade() throws RepositoryException { + RepositorySidegrade sidegrade = new RepositorySidegrade(sourceNodeStore, targetNodeStore); + sidegrade.setIncludes( + "/content/foo/en", + "/content/assets/foo", + "/content/other" + ); + sidegrade.setExcludes( + "/content/assets/foo/2013", + "/content/assets/foo/2012", + "/content/assets/foo/2011", + "/content/assets/foo/2010" + ); + sidegrade.copy(); + } + + private static RepositoryImpl getRepository(NodeStore nodeStore) { + return (RepositoryImpl) new Jcr(new Oak(nodeStore).with(RepositorySidegrade.getSecurityProvider())).createRepository(); + } + + private static void withSession(NodeStore nodeStore, SessionConsumer sessionConsumer) throws RepositoryException { + RepositoryImpl repository = getRepository(nodeStore); + Session session = repository.login(CREDENTIALS); try { - final RepositorySidegrade sidegrade = new RepositorySidegrade(segmentNodeStore, target); - sidegrade.setIncludes( - "/content/foo/en", - "/content/assets/foo", - "/content/other" - ); - sidegrade.setExcludes( - "/content/assets/foo/2013", - "/content/assets/foo/2012", - "/content/assets/foo/2011", - "/content/assets/foo/2010" - ); - sidegrade.copy(); + sessionConsumer.accept((JackrabbitSession) session); + session.save(); } finally { - fileStore.close(); + session.logout(); + repository.shutdown(); + } + } + + private void assertExists(String... paths) throws RepositoryException { + assertExists(targetSession, paths); + + } + + private void assertExists(Session session, String... paths) throws RepositoryException { + for (String path : paths) { + assertTrue("node " + path + " should exist", session.nodeExists(path)); } } + + private void assertMissing(String... paths) throws RepositoryException { + assertMissing(targetSession, paths); + } + + private void assertMissing(Session session, String... paths) throws RepositoryException { + for (String path : paths) { + assertFalse("node " + path + " should not exist", session.nodeExists(path)); + } + } + + private interface SessionConsumer { + void accept(JackrabbitSession session) throws RepositoryException; + } + }