diff --git a/accesscontroltool-bundle/pom.xml b/accesscontroltool-bundle/pom.xml
index baa338f6..c04f74a1 100644
--- a/accesscontroltool-bundle/pom.xml
+++ b/accesscontroltool-bundle/pom.xml
@@ -11,7 +11,7 @@
biz.netcentric.cq.tools.accesscontroltool
accesscontroltool
- 1.9.1
+ 1.9.2
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservice/AceService.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservice/AceService.java
index 777db89e..832b8305 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservice/AceService.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservice/AceService.java
@@ -11,15 +11,23 @@
import java.util.Map;
import java.util.Set;
-import javax.jcr.Session;
-
import biz.netcentric.cq.tools.actool.authorizableutils.AuthorizableInstallationHistory;
import biz.netcentric.cq.tools.actool.installationhistory.AcInstallationHistoryPojo;
public interface AceService {
+ /** Applies the full configuration as stored at the path configured at PID biz.netcentric.cq.tools.actool.aceservice.impl.AceServiceImpl
+ * to the repository.
+ *
+ * @return the history */
public AcInstallationHistoryPojo execute();
+ /** Applies parts of the history
+ *
+ * @param restrictedToPaths only apply ACLs to root paths as given
+ * @return the history */
+ public AcInstallationHistoryPojo execute(String[] restrictedToPaths);
+
/** method that indicates whether the service is ready for installation (if at least one configurations was found in repository)
*
* @return {@code true} if ready, otherwise {@code false} */
@@ -62,13 +70,13 @@ public interface AceService {
/** Common entry point for JMX and install hook.
*
- * @param session
* @param history
* @param configurationFileContentsByFilename
* @param authorizableInstallationHistorySet
+ * @param restrictedToPaths only apply ACLs to root paths as given
* @throws Exception */
- public void installConfigurationFiles(Session session, AcInstallationHistoryPojo history,
+ public void installConfigurationFiles(AcInstallationHistoryPojo history,
Map configurationFileContentsByFilename,
- Set authorizableInstallationHistorySet) throws Exception;
+ Set authorizableInstallationHistorySet, String[] restrictedToPaths) throws Exception;
}
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservice/impl/AceServiceImpl.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservice/impl/AceServiceImpl.java
index 2cd00964..8632da03 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservice/impl/AceServiceImpl.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservice/impl/AceServiceImpl.java
@@ -13,13 +13,13 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
-import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
@@ -69,6 +69,7 @@ public class AceServiceImpl implements AceService {
private static final Logger LOG = LoggerFactory.getLogger(AceServiceImpl.class);
static final String PROPERTY_CONFIGURATION_PATH = "AceService.configurationPath";
+ static final String PROPERTY_INTERMEDIATE_SAVES = "intermediateSaves";
@Reference
AuthorizableCreatorService authorizableCreatorService;
@@ -96,60 +97,150 @@ public class AceServiceImpl implements AceService {
private boolean isExecuting = false;
- @Property(label = "Configuration storage path",
- description = "enter CRX path where ACE configuration gets stored",
- name = AceServiceImpl.PROPERTY_CONFIGURATION_PATH, value = "")
+ @Property(label = "Configuration storage path", description = "enter CRX path where ACE configuration gets stored", name = AceServiceImpl.PROPERTY_CONFIGURATION_PATH, value = "")
private String configurationPath;
+ @Property(label = "Use intermedate saves", description = "Saves ACLs for each path individually - this can be used to avoid problems with large changesets and MongoDB (OAK-5557), however the rollback is disabled then.", name = AceServiceImpl.PROPERTY_INTERMEDIATE_SAVES, value = "")
+ private boolean intermediateSaves;
+
@Activate
- public void activate(final Map,?> properties)
+ public void activate(final Map, ?> properties)
throws Exception {
LOG.debug("Activated AceService!");
modified(properties);
}
@Modified
- public void modified(final Map,?> properties) {
+ public void modified(final Map, ?> properties) {
LOG.debug("Modified AceService!");
configurationPath = PropertiesUtil.toString(properties.get(PROPERTY_CONFIGURATION_PATH), "");
+ LOG.info("Conifg " + PROPERTY_CONFIGURATION_PATH + "=" + configurationPath);
+ intermediateSaves = PropertiesUtil.toBoolean(properties.get(PROPERTY_INTERMEDIATE_SAVES), false);
+ LOG.info("Conifg " + PROPERTY_INTERMEDIATE_SAVES + "=" + intermediateSaves);
}
- private void installAcConfiguration(
- AcConfiguration acConfiguration, AcInstallationHistoryPojo history,
- final Session session,
- Set authorizableHistorySet,
- Map> repositoryDumpAceMap) throws Exception {
+ @Override
+ public AcInstallationHistoryPojo execute() {
+ return execute(null);
+ }
- Map> authorizablesMapfromConfig = acConfiguration.getAuthorizablesConfig();
- Map> aceMapFromConfig = acConfiguration.getAceConfig();
+ @Override
+ public AcInstallationHistoryPojo execute(String[] restrictedToPaths) {
- if (aceMapFromConfig == null) {
- String message = "ace config not found in YAML file! installation aborted!";
- LOG.error(message);
- throw new IllegalArgumentException(message);
+ AcInstallationHistoryPojo history = new AcInstallationHistoryPojo();
+ if (isExecuting) {
+ history.addError("AC Tool is already executing.");
+ return history;
}
- Set authorizablesToRemoveAcesFor = getAuthorizablesToRemoveAcesFor(authorizablesMapfromConfig);
+ Set authorizableInstallationHistorySet = new LinkedHashSet();
+ try {
+ String rootPath = getConfigurationRootPath();
+ Map newestConfigurations = configFilesRetriever.getConfigFileContentFromNode(rootPath);
+ installConfigurationFiles(history, newestConfigurations, authorizableInstallationHistorySet, restrictedToPaths);
+ } catch (AuthorizableCreatorException e) {
+ history.addError(e.toString());
+ // here no rollback of authorizables necessary since session wasn't
+ // saved
+ } catch (Exception e) {
+ // in case an installation of an ACE configuration
+ // threw an exception, logout from this session
+ // otherwise changes made on the ACLs would get persisted
+
+ LOG.error("Exception in AceServiceImpl: {}", e);
+ history.addError(e.toString());
+
+ if (!intermediateSaves) {
+ for (AuthorizableInstallationHistory authorizableInstallationHistory : authorizableInstallationHistorySet) {
+ try {
+ String message = "performing authorizable installation rollback(s)";
+ LOG.info(message);
+ history.addMessage(message);
+ authorizableCreatorService.performRollback(repository,
+ authorizableInstallationHistory, history);
+ } catch (RepositoryException e1) {
+ LOG.error("Exception: ", e1);
+ }
+ }
+ } else {
+ String message = "Rollback is disabled due to configuration option intermediateSaves=true";
+ LOG.info(message);
+ history.addMessage(message);
+ }
- removeAcesForAuthorizables(history, session, authorizablesToRemoveAcesFor, repositoryDumpAceMap);
- installAuthorizables(history, authorizableHistorySet, authorizablesMapfromConfig);
- installAces(history, session, aceMapFromConfig);
+ }
+ return history;
}
- private Set getAuthorizablesToRemoveAcesFor(Map> authorizablesMapfromConfig) {
- Set authorizablesToRemoveAcesFor = new HashSet(authorizablesMapfromConfig.keySet());
- Set authorizablesToBeMigrated = collectAuthorizablesToBeMigrated(authorizablesMapfromConfig);
- Collection> invalidAuthorizablesInConfig = CollectionUtils.intersection(authorizablesToRemoveAcesFor, authorizablesToBeMigrated);
- if (!invalidAuthorizablesInConfig.isEmpty()) {
- String message = "If migrateFrom feature is used, groups that shall be migrated from must not be present in regular configuration (offending groups: "
- + invalidAuthorizablesInConfig + ")";
+ /** Common entry point for JMX and install hook. */
+ @Override
+ public void installConfigurationFiles(AcInstallationHistoryPojo history, Map configurationFileContentsByFilename,
+ Set authorizableInstallationHistorySet, String[] restrictedToPaths)
+ throws Exception {
+
+ String origThreadName = Thread.currentThread().getName();
+ try {
+ Thread.currentThread().setName(origThreadName + "-ACTool-Config-Worker");
+ StopWatch sw = new StopWatch();
+ sw.start();
+ isExecuting = true;
+ String message = "*** Applying AC Tool Configuration...";
+ LOG.info(message);
+ history.addMessage(message);
+
+ if (configurationFileContentsByFilename != null) {
+
+ history.setConfigFileContentsByName(configurationFileContentsByFilename);
+
+ AcConfiguration acConfiguration = configurationMerger.getMergedConfigurations(configurationFileContentsByFilename, history,
+ configReader);
+ history.setAcConfiguration(acConfiguration);
+
+ installMergedConfigurations(history, authorizableInstallationHistorySet, acConfiguration, restrictedToPaths);
+
+ // this runs as "own transaction" after session.save() of ACLs
+ removeObsoleteAuthorizables(history, acConfiguration.getObsoleteAuthorizables());
+
+ }
+ sw.stop();
+ long executionTime = sw.getTime();
+ LOG.info("Successfully applied AC Tool configuration in " + msHumanReadable(executionTime));
+ history.setExecutionTime(executionTime);
+ } catch (Exception e) {
+ history.addError(e.toString()); // ensure exception is added to history before it's persisted in log in finally clause
+ throw e; // handling is different depending on JMX or install hook case
+ } finally {
+ try {
+ acHistoryService.persistHistory(history);
+ } catch (Exception e) {
+ LOG.warn("Could not persist history, e=" + e, e);
+ }
+
+ Thread.currentThread().setName(origThreadName);
+ isExecuting = false;
+ }
+
+ }
+
+ private void installAcConfiguration(
+ AcConfiguration acConfiguration, AcInstallationHistoryPojo history,
+ Set authorizableHistorySet,
+ Map> repositoryDumpAceMap, String[] restrictedToPaths) throws Exception {
+
+ if (acConfiguration.getAceConfig() == null) {
+ String message = "ACE config not found in YAML file! installation aborted!";
LOG.error(message);
throw new IllegalArgumentException(message);
}
- authorizablesToRemoveAcesFor.addAll(authorizablesToBeMigrated);
- return authorizablesToRemoveAcesFor;
+
+
+ installAuthorizables(history, authorizableHistorySet, acConfiguration.getAuthorizablesConfig());
+
+ installAces(history, acConfiguration, repositoryDumpAceMap, restrictedToPaths);
}
+
+
private Set collectAuthorizablesToBeMigrated(Map> authorizablesMapfromConfig) {
Set authorizablesToBeMigrated = new HashSet();
for (String principalStr : authorizablesMapfromConfig.keySet()) {
@@ -164,41 +255,169 @@ private Set collectAuthorizablesToBeMigrated(Map authorizablesInConfig,
- Map> repositoryDumpAceMap) throws UnsupportedRepositoryOperationException, RepositoryException {
+ private void removeAcesForPathsNotInConfig(AcInstallationHistoryPojo history, Session session, Set authorizablesInConfig,
+ Map> repositoryDumpAceMap, Set acePathsFromConfig)
+ throws UnsupportedRepositoryOperationException, RepositoryException {
+
+ int countAcesCleaned = 0;
+ int countPathsCleaned = 0;
+ Set relevantPathsForCleanup = getRelevantPathsForAceCleanup(authorizablesInConfig, repositoryDumpAceMap,
+ acePathsFromConfig);
+
+ for (String relevantPath: relevantPathsForCleanup) {
+ // delete ACE if authorizable *is* in config, but the path *is not* in config
+ int countRemoved = AccessControlUtils.deleteAllEntriesForAuthorizableFromACL(session,
+ relevantPath, authorizablesInConfig.toArray(new String[authorizablesInConfig.size()]));
+ String message = "Cleaned (deleted) " + countRemoved + " ACEs of path " + relevantPath
+ + " from all ACEs for configured authorizables";
+ LOG.info(message);
+ history.addMessage(message);
+ if (countRemoved > 0) {
+ countPathsCleaned++;
+ }
+ countAcesCleaned += countRemoved;
+ }
+
+ if (countAcesCleaned > 0) {
+ String message = "Cleaned " + countAcesCleaned + " ACEs from " + countPathsCleaned
+ + " paths in repository (ACEs that belong to users in the AC Config, "
+ + "but resided at paths that are not contained in AC Config)";
+ LOG.info(message);
+ history.addMessage(message);
+ }
+
+ }
+
+ private Set getRelevantPathsForAceCleanup(Set authorizablesInConfig, Map> repositoryDumpAceMap,
+ Set acePathsFromConfig) {
// loop through all ACLs found in the repository
+ Set relevantPathsForCleanup = new HashSet();
for (Map.Entry> entry : repositoryDumpAceMap.entrySet()) {
Set existingAcl = entry.getValue();
- for (AceBean existingAce : existingAcl) {
- // if the ACL from repo contains an ACE regarding an
- // authorizable from the groups config then delete all ACEs from
- // this authorizable from current ACL
- if (authorizablesInConfig.contains(existingAce.getPrincipalName())) {
- AccessControlUtils.deleteAllEntriesForAuthorizableFromACL(session,
- existingAce.getJcrPath(), existingAce.getPrincipalName());
- String message = "deleted all ACEs of authorizable "
- + existingAce.getPrincipalName()
- + " from ACL of path: " + existingAce.getJcrPath();
- LOG.debug(message);
- history.addVerboseMessage(message);
+ for (AceBean existingAceFromDump : existingAcl) {
+ String jcrPath = existingAceFromDump.getJcrPath();
+
+ if (acePathsFromConfig.contains(jcrPath)) {
+ LOG.debug("Path {} is explicitly listed in config and hence that ACL is handled later, "
+ + "not preceding cleanup needed here", jcrPath);
+ continue;
+ }
+
+ if (!authorizablesInConfig.contains(existingAceFromDump.getPrincipalName())) {
+ LOG.debug("Authorizable {} is not contained in config, hence not cleaning its ACE from non-config-contained "
+ + "path {}", existingAceFromDump.getPrincipalName(), jcrPath);
+ continue;
}
+ relevantPathsForCleanup.add(jcrPath);
}
}
+ return relevantPathsForCleanup;
}
- private void installAces(
- AcInstallationHistoryPojo history,
- final Session session,
- Map> aceMapFromConfig) throws Exception {
+ private Set collectJcrPaths(Map> aceMapFromConfig) {
+ Set jcrPathsInAceConfig = new HashSet();
+ for (Set aces : aceMapFromConfig.values()) {
+ for (AceBean aceBean : aces) {
+ String path = aceBean.getJcrPath();
+ jcrPathsInAceConfig.add(path);
+ }
+ }
+ return jcrPathsInAceConfig;
+ }
+
+ boolean isRelevantPath(String path, String[] restrictedToPaths) {
+ if (restrictedToPaths == null || restrictedToPaths.length == 0) {
+ return true;
+ }
+ boolean isRelevant = false;
+ for (String restrictedToPath : restrictedToPaths) {
+ if (path.matches("^" + restrictedToPath + "(/.*|$)")) {
+ isRelevant = true;
+ }
+ }
+ return isRelevant;
+ }
+
+ private Set getAuthorizablesToRemoveAcesFor(Map> authorizablesMapfromConfig) {
+ Set authorizablesToRemoveAcesFor = new HashSet(authorizablesMapfromConfig.keySet());
+ Set authorizablesToBeMigrated = collectAuthorizablesToBeMigrated(authorizablesMapfromConfig);
+ Collection> invalidAuthorizablesInConfig = CollectionUtils.intersection(authorizablesToRemoveAcesFor, authorizablesToBeMigrated);
+ if (!invalidAuthorizablesInConfig.isEmpty()) {
+ String message = "If migrateFrom feature is used, groups that shall be migrated from must not be present in regular configuration (offending groups: "
+ + invalidAuthorizablesInConfig + ")";
+ LOG.error(message);
+ throw new IllegalArgumentException(message);
+ }
+ authorizablesToRemoveAcesFor.addAll(authorizablesToBeMigrated);
+ return authorizablesToRemoveAcesFor;
+ }
+
+ private void installAces(AcInstallationHistoryPojo history,
+ AcConfiguration acConfiguration, Map> repositoryDumpAceMap, String[] restrictedToPaths) throws Exception {
+
+
+ Map> aceMapFromConfig = acConfiguration.getAceConfig();
+
// --- installation of ACEs from configuration ---
Map> pathBasedAceMapFromConfig = AcHelper
.getPathBasedAceMap(aceMapFromConfig, AcHelper.ACE_ORDER_ACTOOL_BEST_PRACTICE);
- String msg = "*** Starting installation of " + collectAceCount(aceMapFromConfig) + " ACLs for " + aceMapFromConfig.size()
- + " authorizables in content nodes...";
- LOG.info(msg);
- history.addMessage(msg);
- aceBeanInstaller.installPathBasedACEs(pathBasedAceMapFromConfig, session, history);
+ Session session = null;
+ try {
+ session = repository.loginAdministrative(null);
+
+ Set authorizablesToRemoveAcesFor = getAuthorizablesToRemoveAcesFor(acConfiguration.getAuthorizablesConfig());
+ removeAcesForPathsNotInConfig(history, session, authorizablesToRemoveAcesFor, repositoryDumpAceMap,
+ collectJcrPaths(aceMapFromConfig));
+
+ Map> filteredPathBasedAceMapFromConfig = filterForRestrictedPaths(pathBasedAceMapFromConfig,
+ restrictedToPaths, history);
+
+ String msg = "*** Starting installation of " + collectAceCount(filteredPathBasedAceMapFromConfig) + " ACLs for "
+ + filteredPathBasedAceMapFromConfig.size()
+ + " paths in content nodes...";
+ LOG.info(msg);
+ history.addMessage(msg);
+ aceBeanInstaller.installPathBasedACEs(filteredPathBasedAceMapFromConfig, session, history, authorizablesToRemoveAcesFor,
+ intermediateSaves);
+
+ // if everything went fine (no exceptions), save the session
+ // thus persisting the changed ACLs
+ history.addVerboseMessage(
+ "Finished (transient) installation of access control configuration without errors, saving now...");
+ session.save();
+ history.addMessage("Persisted changes of ACLs");
+ } finally {
+ if (session != null) {
+ session.logout();
+ }
+ }
+
+
+ }
+
+ private Map> filterForRestrictedPaths(Map> pathBasedAceMapFromConfig,
+ String[] restrictedToPaths, AcInstallationHistoryPojo history) {
+ if (restrictedToPaths == null || restrictedToPaths.length == 0) {
+ return pathBasedAceMapFromConfig;
+ }
+
+ Map> filteredPathBasedAceMapFromConfig = new HashMap>();
+ for (final String path : pathBasedAceMapFromConfig.keySet()) {
+ boolean isRelevant = isRelevantPath(path, restrictedToPaths);
+ if(isRelevant) {
+ filteredPathBasedAceMapFromConfig.put(path, pathBasedAceMapFromConfig.get(path));
+ }
+ }
+
+ int skipped = pathBasedAceMapFromConfig.keySet().size() - filteredPathBasedAceMapFromConfig.keySet().size();
+ String message = "Will install AC Config at " + filteredPathBasedAceMapFromConfig.keySet().size() + " paths (skipping " + skipped
+ + " due to paths restriction " + Arrays.toString(restrictedToPaths) + ")";
+
+ history.addMessage(message);
+ LOG.info(message);
+
+ return filteredPathBasedAceMapFromConfig;
}
private int collectAceCount(Map> aceMapFromConfig) {
@@ -216,7 +435,10 @@ private void installAuthorizables(
throws RepositoryException, Exception {
// --- installation of Authorizables from configuration ---
- String msg = "*** Starting installation of "+authorizablesMapfromConfig.size()+" authorizables...";
+ StopWatch stopWatch = new StopWatch();
+ stopWatch.start();
+
+ String msg = "*** Starting installation of " + authorizablesMapfromConfig.size() + " authorizables...";
LOG.info(msg);
history.addMessage(msg);
@@ -243,26 +465,30 @@ private void installAuthorizables(
authorizableInstallationHistory);
authorizableInstallationSession.save();
} catch (Exception e) {
- throw e;
+ throw new AuthorizableCreatorException(e);
} finally {
if (authorizableInstallationSession != null) {
authorizableInstallationSession.logout();
}
}
- String message = "Finished installation of authorizables without errors";
+ String message = "Finished installation of authorizables without errors in "
+ + AcInstallationHistoryPojo.msHumanReadable(stopWatch.getTime());
history.addMessage(message);
LOG.info(message);
}
- private void removeObsoleteAuthorizables(AcInstallationHistoryPojo history, Session session, Set obsoleteAuthorizables) {
+ private void removeObsoleteAuthorizables(AcInstallationHistoryPojo history, Set obsoleteAuthorizables) {
+ Session session = null;
try {
+ session = repository.loginAdministrative(null);
+
if (obsoleteAuthorizables.isEmpty()) {
history.addVerboseMessage("No obsolete authorizables configured");
return;
}
-
+
UserManager userManager = AccessControlUtils.getUserManagerAutoSaveDisabled(session);
Set obsoleteAuthorizablesAlreadyPurged = new HashSet();
@@ -291,6 +517,7 @@ private void removeObsoleteAuthorizables(AcInstallationHistoryPojo history, Sess
history.addMessage("(" + obsoleteAuthorizablesAlreadyPurged.size() + " have been purged already)");
}
+
String purgeAuthorizablesResultMsg = purgeAuthorizables(obsoleteAuthorizables, session);
LOG.info(purgeAuthorizablesResultMsg);
history.addVerboseMessage(purgeAuthorizablesResultMsg); // this message is too long for regular log
@@ -299,156 +526,49 @@ private void removeObsoleteAuthorizables(AcInstallationHistoryPojo history, Sess
String excMsg = "Could not purge obsolete authorizables " + obsoleteAuthorizables + ": " + e;
history.addError(excMsg);
LOG.error(excMsg, e);
- }
-
- }
-
- /** Executes the installation of the existing configurations - entry point for JMX execute() method. */
- @Override
- public AcInstallationHistoryPojo execute() {
-
- AcInstallationHistoryPojo history = new AcInstallationHistoryPojo();
- if (isExecuting) {
- history.addError("AC Tool is already executing.");
- return history;
- }
-
- Session session = null;
-
- Set authorizableInstallationHistorySet = new LinkedHashSet();
- try {
- session = repository.loginAdministrative(null);
- String rootPath = getConfigurationRootPath();
- Node rootNode = session.getNode(rootPath);
- Map newestConfigurations = configFilesRetriever.getConfigFileContentFromNode(rootNode);
- installConfigurationFiles(session, history, newestConfigurations, authorizableInstallationHistorySet);
- } catch (AuthorizableCreatorException e) {
- history.addError(e.toString());
- // here no rollback of authorizables necessary since session wasn't
- // saved
- } catch (Exception e) {
- // in case an installation of an ACE configuration
- // threw an exception, logout from this session
- // otherwise changes made on the ACLs would get persisted
-
- session.logout();
-
- LOG.error("Exception in AceServiceImpl: {}", e);
- history.addError(e.toString());
-
- for (AuthorizableInstallationHistory authorizableInstallationHistory : authorizableInstallationHistorySet) {
- try {
- String message = "performing authorizable installation rollback(s)";
- LOG.info(message);
- history.addMessage(message);
- authorizableCreatorService.performRollback(repository,
- authorizableInstallationHistory, history);
- } catch (RepositoryException e1) {
- LOG.error("Exception: ", e1);
- }
- }
} finally {
- session.logout();
- }
- return history;
- }
-
- /** Common entry point for JMX and install hook. */
- @Override
- public void installConfigurationFiles(Session session, AcInstallationHistoryPojo history, Map configurationFileContentsByFilename,
- Set authorizableInstallationHistorySet)
- throws Exception {
-
- String origThreadName = Thread.currentThread().getName();
- try {
- Thread.currentThread().setName(origThreadName + "-ACTool-Config-Worker");
- StopWatch sw = new StopWatch();
- sw.start();
- isExecuting = true;
- String message = "*** Applying AC Tool Configuration...";
- LOG.info(message);
- history.addMessage(message);
-
- if (configurationFileContentsByFilename != null) {
-
- history.setConfigFileContentsByName(configurationFileContentsByFilename);
-
- AcConfiguration acConfiguration = configurationMerger.getMergedConfigurations(configurationFileContentsByFilename, history,
- configReader);
- history.setAcConfiguration(acConfiguration);
-
- installMergedConfigurations(history, session, authorizableInstallationHistorySet, acConfiguration);
-
- // if everything went fine (no exceptions), save the session
- // thus persisting the changed ACLs
- history.addVerboseMessage(
- "Finished (transient) installation of access control configuration without errors, saving now...");
- session.save();
- history.addMessage("Persisted changes of ACLs");
-
- // this runs as "own transaction" after session.save() of ACLs
- removeObsoleteAuthorizables(history, session, acConfiguration.getObsoleteAuthorizables());
+ if (session != null) {
+ session.logout();
}
- sw.stop();
- long executionTime = sw.getTime();
- LOG.info("Successfully applied AC Tool configuration in "+ msHumanReadable(executionTime));
- history.setExecutionTime(executionTime);
- } catch (Exception e) {
- history.addError(e.toString()); // ensure exception is added to history before it's persisted in log in finally clause
- throw e; // handling is different depending on JMX or install hook case
- } finally {
- try {
- acHistoryService.persistHistory(history);
- } catch (Exception e) {
- LOG.warn("Could not persist history, e=" + e, e);
- }
-
- Thread.currentThread().setName(origThreadName);
- isExecuting = false;
+
}
}
private void installMergedConfigurations(
AcInstallationHistoryPojo history,
- Session session,
Set authorizableInstallationHistorySet,
- AcConfiguration acConfiguration) throws ValueFormatException,
+ AcConfiguration acConfiguration, String[] restrictedToPaths) throws ValueFormatException,
RepositoryException, Exception {
+
String message = "Starting installation of merged configurations...";
LOG.debug(message);
history.addVerboseMessage(message);
Map> repositoryDumpAceMap = null;
LOG.debug("Building dump from repository (to compare delta with config to be installed)");
- repositoryDumpAceMap = dumpservice.createAclDumpMap(
- session, AcHelper.PATH_BASED_ORDER,
+ repositoryDumpAceMap = dumpservice.createAclDumpMap(AcHelper.PATH_BASED_ORDER,
AcHelper.ACE_ORDER_NONE,
- dumpservice.getQueryExcludePaths()).getAceDump();
+ new String[0], true).getAceDump();
- installAcConfiguration(acConfiguration, history, session, authorizableInstallationHistorySet, repositoryDumpAceMap);
+ installAcConfiguration(acConfiguration, history, authorizableInstallationHistorySet, repositoryDumpAceMap, restrictedToPaths);
}
@Override
public boolean isReadyToStart() {
String rootPath = getConfigurationRootPath();
- Session session = null;
try {
- session = repository.loginAdministrative(null);
- Node rootNode = session.getNode(rootPath);
- return !configFilesRetriever.getConfigFileContentFromNode(rootNode).isEmpty();
- } catch (Exception e) {
+ return !configFilesRetriever.getConfigFileContentFromNode(rootPath).isEmpty();
- } finally {
- if (session != null) {
- session.logout();
- }
+ } catch (Exception e) {
+ LOG.warn("Could not retrieve config file content for root path " + configurationPath);
+ return false;
}
- return false;
+
}
@Override
@@ -461,7 +581,6 @@ public String purgeACL(String path) {
PurgeHelper.purgeAcl(session, path);
session.save();
} catch (Exception e) {
- // TO DO: Logging
flag = false;
message = e.toString();
LOG.error("Exception: ", e);
@@ -630,19 +749,11 @@ public String getConfigurationRootPath() {
@Override
public Set getCurrentConfigurationPaths() {
- Session session = null;
Set paths = new LinkedHashSet();
-
try {
- session = repository.loginAdministrative(null);
- Node rootNode = session.getNode(configurationPath);
- paths = configFilesRetriever.getConfigFileContentFromNode(rootNode).keySet();
+ paths = configFilesRetriever.getConfigFileContentFromNode(configurationPath).keySet();
} catch (Exception e) {
-
- } finally {
- if (session != null) {
- session.logout();
- }
+ LOG.warn("Could not retrieve config file content for root path " + configurationPath);
}
return paths;
}
@@ -650,8 +761,7 @@ public Set getCurrentConfigurationPaths() {
public Set getAllAuthorizablesFromConfig(Session session)
throws Exception {
AcInstallationHistoryPojo history = new AcInstallationHistoryPojo();
- Node rootNode = session.getNode(configurationPath);
- Map newestConfigurations = configFilesRetriever.getConfigFileContentFromNode(rootNode);
+ Map newestConfigurations = configFilesRetriever.getConfigFileContentFromNode(configurationPath);
AcConfiguration acConfiguration = configurationMerger.getMergedConfigurations(newestConfigurations, history, configReader);
Set allAuthorizablesFromConfig = acConfiguration.getAceConfig().keySet();
return allAuthorizablesFromConfig;
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservicejmx/AceServiceMBean.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservicejmx/AceServiceMBean.java
index 24ea1069..e2c5e78e 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservicejmx/AceServiceMBean.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservicejmx/AceServiceMBean.java
@@ -24,38 +24,43 @@ public interface AceServiceMBean {
boolean isReadyToStart();
- @Description("executes the installation of the ACE configuration(s)")
+ @Description("Executes the installation of the ACE configuration(s)")
String execute();
- @Description("purges the AccessControlList of the given path, if existing")
+ @Description("Executes the installation of the ACE configuration(s), but restricted to given paths")
+ String execute(
+ @Name("paths") @Description("comma separated list of paths to apply the configuration to, other paths will be skipped") String restrictedToPaths);
+
+ @Description("Purges the AccessControlList of the given path, if existing")
+
String purgeACL(@Name("path") final String path);
- @Description("purges all AccessControlLists under the given path and its subpaths, if existing")
+ @Description("Purges all AccessControlLists under the given path and its subpaths, if existing")
String purgeACLs(@Name("path") final String path);
- @Description("purges all authorizables contained in configuration files and all their ACEs from the system")
+ @Description("Purges all authorizables contained in configuration files and all their ACEs from the system")
public String purgeAllAuthorizablesFromConfigurations();
- @Description("provides status and links to the saved history logs")
+ @Description("Provides status and links to the saved history logs")
String[] getSavedLogs() throws RepositoryException;
- @Description("shows execution status of the AC Tool")
+ @Description("Shows execution status of the AC Tool")
public boolean isExecuting();
- @Description("returns a configuration dump containing all groups and all ACLs ordered by path")
+ @Description("Returns a configuration dump containing all groups and all ACLs ordered by path")
public String pathBasedDump();
- @Description("returns a configuration dump containing all groups and all ACEs ordered by groups")
+ @Description("Returns a configuration dump containing all groups and all ACEs ordered by groups (can be used as template for AC Tool configuration file)")
public String groupBasedDump();
- @Description("returns links to the existing configuration files in CRX")
+ @Description("Returns links to the existing configuration files in CRX")
public String[] getConfigurationFiles();
- @Description("returns history log which matches the provided number")
+ @Description("Returns history log which matches the provided number")
public String showHistoryLog(
@Name("historyLogNumber") @Description("number of history log") final String historyLogNumber);
- @Description("purges authorizable(s) and respective ACEs from the system. Several authorizable ids have to be comma separated.")
+ @Description("Purges authorizable(s) and respective ACEs from the system.")
public String purgeAuthorizables(
- @Name("authorizableIds") String authorizableIds);
+ @Name("authorizableIds") @Description("Authorizable IDs to be purged. Several authorizable ids have to be comma separated.") String authorizableIds);
}
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservicejmx/impl/AceServiceMBeanImpl.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservicejmx/impl/AceServiceMBeanImpl.java
index 98b6cd03..97b961e5 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservicejmx/impl/AceServiceMBeanImpl.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceservicejmx/impl/AceServiceMBeanImpl.java
@@ -12,6 +12,7 @@
import javax.management.NotCompliantMBeanException;
+import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.StopWatch;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
@@ -21,13 +22,13 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;
+
import biz.netcentric.cq.tools.actool.aceservice.AceService;
import biz.netcentric.cq.tools.actool.aceservicejmx.AceServiceMBean;
import biz.netcentric.cq.tools.actool.dumpservice.Dumpservice;
import biz.netcentric.cq.tools.actool.installationhistory.AcHistoryService;
-import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;
-
@Service
@Component(immediate = true)
@Properties({
@@ -57,6 +58,15 @@ public String execute() {
return aceService.execute().toString();
}
+ @Override
+ public String execute(String paths) {
+ String[] restrictedToPaths = null;
+ if (StringUtils.isNotBlank(paths)) {
+ restrictedToPaths = paths.split(",");
+ }
+ return aceService.execute(restrictedToPaths).toString();
+ }
+
@Override
public boolean isReadyToStart() {
return aceService.isReadyToStart();
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/acls/AceBeanInstaller.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/acls/AceBeanInstaller.java
index 726d4410..feebcbf5 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/acls/AceBeanInstaller.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/acls/AceBeanInstaller.java
@@ -25,7 +25,10 @@ public interface AceBeanInstaller {
*
* @param pathBasedAceMapFromConfig map containing the ACE data from the merged configurations path based
* @param session the jcr session
- * @param history history object */
- void installPathBasedACEs(final Map> pathBasedAceMapFromConfig, final Session session, final AcInstallationHistoryPojo history) throws Exception;
+ * @param history history object
+ * @param authorizablesToRemoveAcesFor
+ * @param intermediateSaves whether the session should be saved after each path (for each ACL) */
+ void installPathBasedACEs(final Map> pathBasedAceMapFromConfig, final Session session,
+ final AcInstallationHistoryPojo history, Set authorizablesToRemoveAcesFor, boolean intermediateSaves) throws Exception;
}
\ No newline at end of file
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/acls/AceBeanInstallerImpl.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/acls/AceBeanInstallerImpl.java
index 8466d867..47bb7bb7 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/acls/AceBeanInstallerImpl.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/acls/AceBeanInstallerImpl.java
@@ -58,15 +58,22 @@ public class AceBeanInstallerImpl implements AceBeanInstaller {
public void installPathBasedACEs(
final Map> pathBasedAceMapFromConfig,
final Session session,
- final AcInstallationHistoryPojo history) throws Exception {
+ final AcInstallationHistoryPojo history, Set authorizablesToRemoveAcesFor,
+ boolean intermediateSaves) throws Exception {
final Set paths = pathBasedAceMapFromConfig.keySet();
- LOG.debug("Paths in merged config = {}", paths);
final String msg = "Found " + paths.size() + " paths in config";
LOG.debug(msg);
history.addVerboseMessage(msg);
+ LOG.trace("Paths with ACEs: {}", paths);
+
+ if (intermediateSaves) {
+ final String messageSave = "Will save ACL for each path to session due to configuration option intermediateSaves=true - rollback functionality is disabled.";
+ LOG.info(messageSave);
+ history.addMessage(messageSave);
+ }
// loop through all nodes from config
for (final String path : paths) {
@@ -90,19 +97,21 @@ public void installPathBasedACEs(
new AcePermissionComparator());
orderedAceBeanSetFromConfig.addAll(aceBeanSetFromConfig);
- // remove ACL of that path from ACLs from repo so that after the
- // loop has ended only paths are left which are not contained in
- // current config
- for (final AceBean bean : orderedAceBeanSetFromConfig) {
- AccessControlUtils.deleteAllEntriesForAuthorizableFromACL(session,
- path, bean.getPrincipalName());
- final String message = "deleted all ACEs of authorizable "
- + bean.getPrincipalName()
- + " from ACL of path: " + path;
- LOG.debug(message);
- history.addVerboseMessage(message);
- }
+ // Remove all config contained auhtorizables from ACL of this path
+ int countRemoved = AccessControlUtils.deleteAllEntriesForAuthorizableFromACL(session,
+ path, authorizablesToRemoveAcesFor.toArray(new String[authorizablesToRemoveAcesFor.size()]));
+ final String message = "Deleted " + countRemoved + " ACEs for configured authorizables from path " + path;
+ LOG.debug(message);
+ history.addVerboseMessage(message);
+
writeAcBeansToRepository(session, history, orderedAceBeanSetFromConfig);
+
+ if (intermediateSaves) {
+ final String messageSave = "Saved session for path " + path;
+ LOG.debug(messageSave);
+ history.addVerboseMessage(messageSave);
+ session.save();
+ }
}
}
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/authorizableutils/AuthorizableCreatorException.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/authorizableutils/AuthorizableCreatorException.java
index 6fc71bff..5e1999fa 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/authorizableutils/AuthorizableCreatorException.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/authorizableutils/AuthorizableCreatorException.java
@@ -12,4 +12,8 @@ public class AuthorizableCreatorException extends Exception {
public AuthorizableCreatorException(String message) {
super(message);
}
+
+ public AuthorizableCreatorException(Throwable e) {
+ super(e);
+ }
}
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/authorizableutils/impl/AuthorizableCreatorServiceImpl.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/authorizableutils/impl/AuthorizableCreatorServiceImpl.java
index f8bd976c..00a4e0de 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/authorizableutils/impl/AuthorizableCreatorServiceImpl.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/authorizableutils/impl/AuthorizableCreatorServiceImpl.java
@@ -61,8 +61,6 @@ public class AuthorizableCreatorServiceImpl implements
private static final Logger LOG = LoggerFactory.getLogger(AuthorizableCreatorServiceImpl.class);
- private static final String PATH_HOME_GROUPS = "/home/groups";
- private static final String PATH_HOME_USERS = "/home/users";
private static final String PATH_SEGMENT_SYSTEMUSERS = "system";
private static final String PRINCIPAL_EVERYONE = "everyone";
@@ -76,17 +74,17 @@ public void createNewAuthorizables(
Map> principalMapFromConfig,
final Session session, AcInstallationHistoryPojo status,
AuthorizableInstallationHistory authorizableInstallationHistory)
- throws AccessDeniedException,
- UnsupportedRepositoryOperationException, RepositoryException,
- AuthorizableCreatorException {
+ throws AccessDeniedException,
+ UnsupportedRepositoryOperationException, RepositoryException,
+ AuthorizableCreatorException {
this.status = status;
this.principalMapFromConfig = principalMapFromConfig;
this.authorizableInstallationHistory = authorizableInstallationHistory;
- Set groupsFromConfigurations = principalMapFromConfig.keySet();
+ Set authorizableFromConfigurations = principalMapFromConfig.keySet();
- for (String principalId : groupsFromConfigurations) {
+ for (String principalId : authorizableFromConfigurations) {
Set currentPrincipalData = principalMapFromConfig
.get(principalId);
@@ -112,9 +110,9 @@ private void installAuthorizableConfigurationBean(final Session session,
AuthorizableConfigBean authorizableConfigBean,
AcInstallationHistoryPojo history,
AuthorizableInstallationHistory authorizableInstallationHistory)
- throws AccessDeniedException,
- UnsupportedRepositoryOperationException, RepositoryException,
- AuthorizableExistsException, AuthorizableCreatorException {
+ throws AccessDeniedException,
+ UnsupportedRepositoryOperationException, RepositoryException,
+ AuthorizableExistsException, AuthorizableCreatorException {
String principalId = authorizableConfigBean.getPrincipalID();
LOG.debug("- start installation of authorizable: {}", principalId);
@@ -208,8 +206,6 @@ private void migrateFromOldGroup(AuthorizableConfigBean authorizableConfigBean,
}
-
-
private void handleIntermediatePath(final Session session,
AuthorizableConfigBean principalConfigBean,
AcInstallationHistoryPojo history,
@@ -225,17 +221,20 @@ private void handleIntermediatePath(final Session session,
.substring(0, existingAuthorizable.getPath().lastIndexOf("/"));
// Relative paths need to be prefixed with /home/groups (issue #10)
String authorizablePathFromBean = principalConfigBean.getPath();
- if (StringUtils.isNotEmpty(authorizablePathFromBean) && authorizablePathFromBean.charAt(0) != '/') {
- authorizablePathFromBean = (principalConfigBean.isGroup() ? PATH_HOME_GROUPS : PATH_HOME_USERS)
+ if (StringUtils.isNotEmpty(authorizablePathFromBean) && (authorizablePathFromBean.charAt(0) != '/')) {
+ authorizablePathFromBean = (principalConfigBean.isGroup() ? Constants.GROUPS_ROOT : Constants.USERS_ROOT)
+ (principalConfigBean.isSystemUser() && !authorizablePathFromBean.startsWith(PATH_SEGMENT_SYSTEMUSERS)
? "/" + PATH_SEGMENT_SYSTEMUSERS : "")
+ "/" + authorizablePathFromBean;
}
- if (!StringUtils.equals(intermediatedPathOfExistingAuthorizable, authorizablePathFromBean)) {
+ if (!StringUtils.equals(intermediatedPathOfExistingAuthorizable, authorizablePathFromBean)
+ && StringUtils.isNotBlank(principalConfigBean.getPath())) {
StringBuilder message = new StringBuilder();
message.append("found change of intermediate path:\n"
- + "existing authorizable: " + existingAuthorizable.getID() + " has intermediate path: " + intermediatedPathOfExistingAuthorizable +"\n"
- + "authorizable from config: " + principalConfigBean.getPrincipalID() + " has intermediate path: " + authorizablePathFromBean
+ + "existing authorizable: " + existingAuthorizable.getID() + " has intermediate path: "
+ + intermediatedPathOfExistingAuthorizable + "\n"
+ + "authorizable from config: " + principalConfigBean.getPrincipalID() + " has intermediate path: "
+ + authorizablePathFromBean
+ "\n");
// save members of existing group before deletion
@@ -291,16 +290,16 @@ private void handleIntermediatePath(final Session session,
* @throws AccessDeniedException */
private void deleteOldIntermediatePath(final Session session,
Node oldIntermediateNode) throws RepositoryException,
- PathNotFoundException, VersionException, LockException,
- ConstraintViolationException, AccessDeniedException {
+ PathNotFoundException, VersionException, LockException,
+ ConstraintViolationException, AccessDeniedException {
// if '/home/groups' or '/home/users' was intermediatedNode, these must
// not get deleted!
// also node to be deleted has to be empty, so no other authorizables
// stored under this path get deleted
- while (!StringUtils.equals(PATH_HOME_GROUPS,
+ while (!StringUtils.equals(Constants.GROUPS_ROOT,
oldIntermediateNode.getPath())
- && !StringUtils.equals(PATH_HOME_USERS,
+ && !StringUtils.equals(Constants.USERS_ROOT,
oldIntermediateNode.getPath())
&& !oldIntermediateNode.hasNodes()) {
// delete old intermediatedPath
@@ -351,8 +350,8 @@ private Authorizable createNewAuthorizable(
AcInstallationHistoryPojo status,
AuthorizableInstallationHistory authorizableInstallationHistory,
UserManager userManager, ValueFactory vf, Session session)
- throws AuthorizableExistsException, RepositoryException,
- AuthorizableCreatorException {
+ throws AuthorizableExistsException, RepositoryException,
+ AuthorizableCreatorException {
boolean isGroup = principalConfigBean.isGroup();
String principalId = principalConfigBean.getPrincipalID();
@@ -405,8 +404,8 @@ void mergeMemberOfGroups(String principalId,
AcInstallationHistoryPojo status, UserManager userManager,
Set membershipGroupsFromConfig,
Set membershipGroupsFromRepository)
- throws RepositoryException, AuthorizableExistsException,
- AuthorizableCreatorException {
+ throws RepositoryException, AuthorizableExistsException,
+ AuthorizableCreatorException {
LOG.debug("mergeMemberOfGroups() for {}", principalId);
// membership to everyone cannot be removed or added => take it out from both lists
@@ -434,7 +433,7 @@ void mergeMemberOfGroups(String principalId,
Iterator toBeRemovedMembersIt = toBeRemovedMembers.iterator();
while (toBeRemovedMembersIt.hasNext()) {
String groupId = toBeRemovedMembersIt.next();
- if (ignoredMembershipsPattern != null && ignoredMembershipsPattern.matcher(groupId).find()) {
+ if ((ignoredMembershipsPattern != null) && ignoredMembershipsPattern.matcher(groupId).find()) {
toBeSkippedFromRemovalMembers.add(groupId);
toBeRemovedMembersIt.remove();
}
@@ -483,8 +482,8 @@ private Authorizable createNewGroup(
AuthorizableInstallationHistory authorizableInstallationHistory,
ValueFactory vf,
Map> principalMapFromConfig, Session session)
- throws AuthorizableExistsException, RepositoryException,
- AuthorizableCreatorException {
+ throws AuthorizableExistsException, RepositoryException,
+ AuthorizableCreatorException {
String groupID = principalConfigBean.getPrincipalID();
String intermediatePath = principalConfigBean.getPath();
@@ -492,8 +491,13 @@ private Authorizable createNewGroup(
// create new Group
Group newGroup = null;
try {
- newGroup = userManager.createGroup(new PrincipalImpl(groupID),
- intermediatePath);
+ PrincipalImpl principalForNewGroup = new PrincipalImpl(groupID);
+ if (StringUtils.isNotBlank(intermediatePath)) {
+ newGroup = userManager.createGroup(principalForNewGroup, intermediatePath);
+ } else {
+ newGroup = userManager.createGroup(principalForNewGroup);
+ }
+
} catch (AuthorizableExistsException e) {
LOG.warn("Group {} already exists in system!", groupID);
newGroup = (Group) userManager.getAuthorizable(groupID);
@@ -501,14 +505,13 @@ private Authorizable createNewGroup(
addMembersToReferencingAuthorizables(newGroup, principalConfigBean, userManager);
-
setAuthorizableProperties(newGroup, vf, principalConfigBean, session);
return newGroup;
}
private void setAuthorizableProperties(Authorizable authorizable, ValueFactory vf, AuthorizableConfigBean principalConfigBean,
Session session)
- throws RepositoryException {
+ throws RepositoryException {
String profileContent = principalConfigBean.getProfileContent();
if (StringUtils.isNotBlank(profileContent)) {
@@ -537,7 +540,7 @@ private void setAuthorizableProperties(Authorizable authorizable, ValueFactory v
authorizable.setProperty("profile/aboutMe", vf.createValue(description));
}
}
-
+
private Authorizable createNewUser(
final UserManager userManager,
AuthorizableConfigBean principalConfigBean,
@@ -545,8 +548,8 @@ private Authorizable createNewUser(
AuthorizableInstallationHistory authorizableInstallationHistory,
ValueFactory vf,
Map> principalMapFromConfig, Session session)
- throws AuthorizableExistsException, RepositoryException,
- AuthorizableCreatorException {
+ throws AuthorizableExistsException, RepositoryException,
+ AuthorizableCreatorException {
String principalId = principalConfigBean.getPrincipalID();
String password = principalConfigBean.getPassword();
boolean isSystemUser = principalConfigBean.isSystemUser();
@@ -587,7 +590,7 @@ private void addMembersToReferencingAuthorizables(Authorizable authorizable, Aut
// using reflection with fallback to create a system user in order to be backwards compatible
private User userManagerCreateSystemUserViaReflection(UserManager userManager, String userID, String intermediatePath,
AcInstallationHistoryPojo status)
- throws RepositoryException {
+ throws RepositoryException {
// make sure all relative intermediate paths get the prefix suffix (but don't touch absolute paths)
String systemPrefix = "system/";
@@ -611,7 +614,7 @@ private User userManagerCreateSystemUserViaReflection(UserManager userManager, S
}
/** Validates the authorizables in 'membersOf' array of a given authorizable. Validation fails if an authorizable is a user.
- *
+ *
* If an authorizable contained in membersOf array doesn't exist it gets created and the current authorizable gets added as a member.
*
* @param userManager
@@ -623,7 +626,7 @@ private User userManagerCreateSystemUserViaReflection(UserManager userManager, S
Set validateAssignedGroups(
final UserManager userManager, final String authorizablelID,
final Set isMemberOf) throws RepositoryException,
- AuthorizableCreatorException {
+ AuthorizableCreatorException {
Set authorizableSet = new HashSet();
for (String memberOfPrincipal : isMemberOf) {
@@ -711,17 +714,17 @@ public void performRollback(SlingRepository repository,
history.addWarning("performing Groups rollback!");
for (String authorizableName : newCreatedAuthorizables) {
- Authorizable authorizable = userManager.getAuthorizable(authorizableName);
- if (authorizable != null) {
- authorizable.remove();
- message = "removed authorizable " + authorizableName + " from the system!";
- LOG.info(message);
- history.addWarning(message);
- } else {
- message = "Can't remove authorizable " + authorizableName + " from the system!";
- LOG.error(message);
- history.addError(message);
- }
+ Authorizable authorizable = userManager.getAuthorizable(authorizableName);
+ if (authorizable != null) {
+ authorizable.remove();
+ message = "removed authorizable " + authorizableName + " from the system!";
+ LOG.info(message);
+ history.addWarning(message);
+ } else {
+ message = "Can't remove authorizable " + authorizableName + " from the system!";
+ LOG.error(message);
+ history.addError(message);
+ }
}
}
@@ -783,7 +786,7 @@ public void performRollback(SlingRepository repository,
if (authorizable.hasProperty("profile/givenName")) {
authorizableName = authorizable
.getProperty("profile/givenName")[0]
- .getString();
+ .getString();
}
if (snapshotBean.getName().equals(authorizableName)) {
history.addMessage("No change found in name of authorizable: "
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/ConfigFilesRetriever.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/ConfigFilesRetriever.java
index 46e672df..043a35e1 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/ConfigFilesRetriever.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/ConfigFilesRetriever.java
@@ -2,8 +2,6 @@
import java.util.Map;
-import javax.jcr.Node;
-
import org.apache.jackrabbit.vault.fs.io.Archive;
/** Retrieves the contents of a AC tool yaml config file from either a package directly (used by install hook) or from the JCR node structure
@@ -12,12 +10,13 @@
* @author ghenzler */
public interface ConfigFilesRetriever {
- /** Returns yaml configurations using a given root node. This will only return configuration entries which apply to the current run mode.
+ /** Returns yaml configurations using a given root node. This will only return configuration entries which apply to the current run
+ * mode.
*
- * @param rootNode the root node in the JCR to start looking for yaml-files
+ * @param rootPath the root path in the JCR to start looking for yaml-files
* @return map of yaml configurations by their path location
* @throws Exception if things go wrong */
- Map getConfigFileContentFromNode(Node rootNode) throws Exception;
+ Map getConfigFileContentFromNode(String rootPath) throws Exception;
/** Returns yaml configurations from a package. This will only return configuration entries which apply to the current run mode
*
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/ConfigFilesRetrieverImpl.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/ConfigFilesRetrieverImpl.java
index f49a272c..8ad4caab 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/ConfigFilesRetrieverImpl.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/ConfigFilesRetrieverImpl.java
@@ -12,6 +12,7 @@
import java.util.Set;
import javax.jcr.Node;
+import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
import org.apache.commons.io.IOUtils;
@@ -22,6 +23,7 @@
import org.apache.jackrabbit.commons.JcrUtils;
import org.apache.jackrabbit.vault.fs.io.Archive;
import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
+import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.settings.SlingSettingsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,13 +37,30 @@ public class ConfigFilesRetrieverImpl implements ConfigFilesRetriever {
@Reference
private SlingSettingsService slingSettingsService;
+
+ @Reference
+ private SlingRepository repository;
+
@Override
- public Map getConfigFileContentFromNode(Node rootNode) throws Exception {
- if (rootNode == null) {
- throw new IllegalArgumentException("No configuration path configured! please check the configuration of AcService!");
+ public Map getConfigFileContentFromNode(String rootPath) throws Exception {
+
+ Session session = null;
+ try {
+ session = repository.loginAdministrative(null);
+
+ Node rootNode = session.getNode(rootPath);
+
+ if (rootNode == null) {
+ throw new IllegalArgumentException("No configuration path configured! please check the configuration of AcService!");
+ }
+ Map configurations = getConfigurations(new NodeInJcr(rootNode));
+ return configurations;
+ } finally {
+ if (session != null) {
+ session.logout();
+ }
}
- Map configurations = getConfigurations(new NodeInJcr(rootNode));
- return configurations;
+
}
@Override
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMerger.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMerger.java
index 2d518f64..fe72f5ad 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMerger.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMerger.java
@@ -28,6 +28,7 @@
import biz.netcentric.cq.tools.actool.configmodel.AceBean;
import biz.netcentric.cq.tools.actool.configmodel.AuthorizableConfigBean;
import biz.netcentric.cq.tools.actool.configmodel.GlobalConfiguration;
+import biz.netcentric.cq.tools.actool.helper.Constants;
import biz.netcentric.cq.tools.actool.installationhistory.AcInstallationHistoryPojo;
import biz.netcentric.cq.tools.actool.validators.AceBeanValidator;
import biz.netcentric.cq.tools.actool.validators.AuthorizableValidator;
@@ -57,7 +58,7 @@ public AcConfiguration getMergedConfigurations(
final Map configFileContentByFilename,
final AcInstallationHistoryPojo history,
final ConfigReader configReader) throws RepositoryException,
- AcConfigBeanValidationException {
+ AcConfigBeanValidationException {
final GlobalConfiguration globalConfiguration = new GlobalConfiguration();
final Map> mergedAuthorizablesMapfromConfig = new LinkedHashMap>();
@@ -101,8 +102,7 @@ public AcConfiguration getMergedConfigurations(
// --- authorizables config section
- // build AuthorizableConfigBeans from current configurations
- final AuthorizableValidator authorizableValidator = new AuthorizableValidatorImpl();
+ final AuthorizableValidator authorizableValidator = new AuthorizableValidatorImpl(Constants.GROUPS_ROOT, Constants.USERS_ROOT);
final Map> groupAuthorizablesMapFromConfig = configReader.getGroupConfigurationBeans(
yamlRootList, authorizableValidator);
// add AuthorizableConfigBeans built from current configuration to set containing AuthorizableConfigBeans from all
@@ -156,7 +156,7 @@ public AcConfiguration getMergedConfigurations(
// set member groups
final AuthorizableMemberGroupsValidator membersValidator = new AuthorizableMemberGroupsValidator();
membersValidator.validate(mergedAuthorizablesMapfromConfig);
-
+
GlobalConfigurationValidator.validate(globalConfiguration);
AcConfiguration acConfiguration = new AcConfiguration();
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/dumpservice/Dumpservice.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/dumpservice/Dumpservice.java
index f796c7b8..83f2cc86 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/dumpservice/Dumpservice.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/dumpservice/Dumpservice.java
@@ -15,7 +15,6 @@
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
-import javax.jcr.ValueFormatException;
import biz.netcentric.cq.tools.actool.configmodel.AuthorizableConfigBean;
import biz.netcentric.cq.tools.actool.helper.AclBean;
@@ -28,7 +27,7 @@ public Set getGroupBeans(Session session)
public boolean isIncludeUsers();
- /** returns the paths under jcr:root witch are excluded from search for rep:policy nodes in OSGi configuration
+ /** returns the paths under jcr:root which are excluded from search for rep:policy nodes in OSGi configuration
*
* @return String array containing the paths */
public String[] getQueryExcludePaths();
@@ -42,16 +41,14 @@ public Set getACLDumpBeans(final Session session)
/** returns a Map with holds either principal or path based ACE data
*
- * @param session the jcr session
* @param keyOrder either principals (AceHelper.PRINCIPAL_BASED_ORDERING) or node paths (AceHelper.PATH_BASED_ORDERING) as keys
* @param aclOrdering specifies whether the allow and deny ACEs within an ACL should be divided in separate blocks (first deny then
* allow)
+ * @param isIncludeUsers
* @return AceDumpData */
- public AceDumpData createAclDumpMap(final Session session,
- final int keyOrder, final int aclOrdering,
- final String[] excludePaths) throws ValueFormatException,
- IllegalArgumentException, IllegalStateException,
- RepositoryException;
+ public AceDumpData createAclDumpMap( final int keyOrder, final int aclOrdering,
+ final String[] excludePaths,
+ final boolean isIncludeUsers) throws RepositoryException;
/** method that return a dump comprising of all groups and all aces in path based view
*
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/dumpservice/impl/DumpserviceImpl.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/dumpservice/impl/DumpserviceImpl.java
index c7d99809..682dcc1a 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/dumpservice/impl/DumpserviceImpl.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/dumpservice/impl/DumpserviceImpl.java
@@ -253,15 +253,14 @@ private String getCompleteDump(int keyOrder, int aclOrderInMap) {
LOG.info("Starting to create dump for "
+ (keyOrder == AcHelper.PRINCIPAL_BASED_ORDER ? "PRINCIPAL_BASED_ORDER" : "PATH_BASED_ORDER"));
try {
- session = repository.loginAdministrative(null);
- AceDumpData aceDumpData = createAclDumpMap(session,
+
+ AceDumpData aceDumpData = createAclDumpMap(
keyOrder, AcHelper.ACE_ORDER_ACTOOL_BEST_PRACTICE, // this ORDER is important to keep the ORDER of denies with "keepOrder"
// attribute that is automatically added if needed
queryExcludePaths);
Map> aclDumpMap = aceDumpData.getAceDump();
- // Map> legacyAclDumpMap =
- // aceDumpData.getLegacyAceDump();
+ session = repository.loginAdministrative(null);
Set groupBeans = getGroupBeans(session);
Set usersFromACEs = getUsersFromAces(keyOrder, session, aclDumpMap);
Set userBeans = getUserBeans(usersFromACEs);
@@ -269,10 +268,9 @@ private String getCompleteDump(int keyOrder, int aclOrderInMap) {
String configurationDumpAsString = getConfigurationDumpAsString(aceDumpData, groupBeans,
userBeans, aclOrderInMap);
return configurationDumpAsString;
- } catch (ValueFormatException e) {
- LOG.error("ValueFormatException in AceServiceImpl: {}", e);
+
} catch (IllegalStateException e) {
- LOG.error("IllegalStateException in AceServiceImpl: {}", e);
+ LOG.error("IllegalStateException in DumpServiceImpl: {}", e);
} catch (IOException e) {
LOG.error("IOException in AceServiceImpl: {}", e);
} catch (RepositoryException e) {
@@ -395,13 +393,11 @@ public Set getACLDumpBeans(final Session session)
return accessControBeanSet;
}
- @Override
- public AceDumpData createAclDumpMap(final Session session,
- final int keyOrder, final int aclOrdering,
+ public AceDumpData createAclDumpMap(final int keyOrder, final int aclOrdering,
final String[] excludePaths) throws ValueFormatException,
IllegalArgumentException, IllegalStateException,
RepositoryException {
- return createAclDumpMap(session, keyOrder, aclOrdering, excludePaths, includeUsersInDumps);
+ return createAclDumpMap(keyOrder, aclOrdering, excludePaths, includeUsersInDumps);
}
/** returns a Map with holds either principal or path based ACE data
@@ -413,75 +409,82 @@ public AceDumpData createAclDumpMap(final Session session,
* @param isFilterACEs
* @param isIncludeUsers
* @return
- * @throws ValueFormatException
- * @throws IllegalStateException
* @throws RepositoryException */
- private AceDumpData createAclDumpMap(final Session session,
- final int keyOrder, final int aclOrdering,
+ @Override
+ public AceDumpData createAclDumpMap(final int keyOrder, final int aclOrdering,
final String[] excludePaths,
- final boolean isIncludeUsers) throws ValueFormatException,
- IllegalArgumentException, IllegalStateException,
- RepositoryException {
- AceDumpData aceDumpData = new AceDumpData();
- UserManager um = ((JackrabbitSession) session).getUserManager();
- Map> aceMap = null;
- Map> legacyAceMap = new TreeMap>();
+ final boolean isIncludeUsers) throws RepositoryException {
+ Session session = null;
+ try {
+ session = repository.loginAdministrative(null);
- if (keyOrder == AcHelper.PRINCIPAL_BASED_ORDER) { // principal based
- aceMap = new TreeMap>();
- } else if (keyOrder == AcHelper.PATH_BASED_ORDER) { // path based
- aceMap = new TreeMap>();
- }
+ AceDumpData aceDumpData = new AceDumpData();
+ UserManager um = ((JackrabbitSession) session).getUserManager();
+ Map> aceMap = null;
+ Map> legacyAceMap = new TreeMap>();
- Set aclBeanSet = getACLDumpBeans(session);
+ if (keyOrder == AcHelper.PRINCIPAL_BASED_ORDER) { // principal based
+ aceMap = new TreeMap>();
+ } else if (keyOrder == AcHelper.PATH_BASED_ORDER) { // path based
+ aceMap = new TreeMap>();
+ }
- // build a set containing all ACE found in the original order
- for (AclBean aclBean : aclBeanSet) {
+ Set aclBeanSet = getACLDumpBeans(session);
- if (aclBean.getAcl() == null) {
- continue;
- }
+ // build a set containing all ACE found in the original order
+ for (AclBean aclBean : aclBeanSet) {
- boolean allowExistsInListEarlier = false;
- for (AccessControlEntry ace : aclBean.getAcl()
- .getAccessControlEntries()) {
- if (!(ace instanceof JackrabbitAccessControlEntry)) {
- throw new IllegalStateException("AC entry is not a JackrabbitAccessControlEntry: " + ace);
+ if (aclBean.getAcl() == null) {
+ continue;
}
- AceWrapper tmpBean = new AceWrapper((JackrabbitAccessControlEntry) ace, aclBean.getJcrPath());
- AceBean tmpAceBean = AcHelper.getAceBean(tmpBean);
-
- // sets keepOrder true if ACE deny entries are found that are not at top of list
- if (tmpAceBean.isAllow()) {
- allowExistsInListEarlier = true;
- } else {
- if (allowExistsInListEarlier && !tmpAceBean.isAllow()) {
- tmpAceBean.setKeepOrder(true);
+
+ boolean allowExistsInListEarlier = false;
+ for (AccessControlEntry ace : aclBean.getAcl()
+ .getAccessControlEntries()) {
+ if (!(ace instanceof JackrabbitAccessControlEntry)) {
+ throw new IllegalStateException("AC entry is not a JackrabbitAccessControlEntry: " + ace);
+ }
+ AceWrapper tmpBean = new AceWrapper((JackrabbitAccessControlEntry) ace, aclBean.getJcrPath());
+ AceBean tmpAceBean = AcHelper.getAceBean(tmpBean);
+
+ // sets keepOrder true if ACE deny entries are found that are not at top of list
+ if (tmpAceBean.isAllow()) {
+ allowExistsInListEarlier = true;
+ } else {
+ if (allowExistsInListEarlier && !tmpAceBean.isAllow()) {
+ tmpAceBean.setKeepOrder(true);
+ }
}
- }
- Authorizable authorizable = um.getAuthorizable(tmpAceBean
- .getPrincipalName());
+ Authorizable authorizable = um.getAuthorizable(tmpAceBean
+ .getPrincipalName());
- // if this group exists under home
- if (authorizable != null) {
- if (authorizable.isGroup() || isIncludeUsers) {
- addBeanToMap(keyOrder, aclOrdering, aceMap, tmpAceBean);
+ // if this group exists under home
+ if (authorizable != null) {
+ if (authorizable.isGroup() || isIncludeUsers) {
+ addBeanToMap(keyOrder, aclOrdering, aceMap, tmpAceBean);
+ }
}
+ // otherwise put in map holding legacy ACEs
+ else {
+ addBeanToMap(keyOrder, aclOrdering, legacyAceMap,
+ tmpAceBean);
+ }
+
}
- // otherwise put in map holding legacy ACEs
- else {
- addBeanToMap(keyOrder, aclOrdering, legacyAceMap,
- tmpAceBean);
- }
+ }
+
+ aceDumpData.setAceDump(aceMap);
+ aceDumpData.setLegacyAceDump(legacyAceMap);
+ return aceDumpData;
+
+ } finally {
+ if (session != null) {
+ session.logout();
}
}
- aceDumpData.setAceDump(aceMap);
- aceDumpData.setLegacyAceDump(legacyAceMap);
-
- return aceDumpData;
}
private void addBeanToMap(final int keyOrder, final int aclOrdering,
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/AcHelper.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/AcHelper.java
index c29b7ae9..8f9e9cab 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/AcHelper.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/AcHelper.java
@@ -49,10 +49,10 @@ private AcHelper() {
/** By default ACEs with denies are sorted up to the top of the list, this follows the best practice to order denies always before
* allows - this makes by default allows always take precedence over denies.
- *
+ *
* Denies should be used sparsely: Normally there is exactly one group that includes all deny-ACEs for to-be-secured content and many
* groups with allow-ACEs, that selectively allow what has been denied by the "global deny" group.
- *
+ *
* For some special cases (e.g. when working with restrictions that limit a preceding allow) it is possible to specify "keepOrder=true",
* for those cases the natural order from the config file is kept when {@link #ACE_ORDER_ACTOOL_BEST_PRACTICE} is used. */
public static int ACE_ORDER_ACTOOL_BEST_PRACTICE = 1;
@@ -116,7 +116,8 @@ public static Principal getPrincipal(final Session session,
principal = getPrincipalForName(session, principalName);
if (principal == null) {
- final String query = "/jcr:root/home/groups//*[(@jcr:primaryType = 'rep:Group') and jcr:like(@rep:principalName, 'cn="
+ final String query = "/jcr:root" + Constants.GROUPS_ROOT
+ + "//*[(@jcr:primaryType = 'rep:Group') and jcr:like(@rep:principalName, 'cn="
+ principalName + "%')]";
LOG.debug("Fallback query did not return results for principalName={}, using second fallback query (ldap name): {}",
principalName, query);
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/AccessControlUtils.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/AccessControlUtils.java
index 0c6b2308..9a44870e 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/AccessControlUtils.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/AccessControlUtils.java
@@ -26,7 +26,7 @@
import javax.jcr.security.AccessControlPolicyIterator;
import javax.jcr.security.Privilege;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.ArrayUtils;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
@@ -230,9 +230,10 @@ public static Set getPrivilegeSet(String[] privNames,
/** @param session admin session
* @param path valid node path in CRX
- * @param authorizableID ID of authorizable to be deleted from ACL of node specified by path */
- public static void deleteAllEntriesForAuthorizableFromACL(final Session session,
- final String path, String authorizableID)
+ * @param authorizableIds ids of authorizables to be deleted from ACL of node specified by path
+ * @return count ACEs that were removed */
+ public static int deleteAllEntriesForAuthorizableFromACL(final Session session,
+ final String path, String[] authorizableIds)
throws UnsupportedRepositoryOperationException, RepositoryException {
final AccessControlManager accessControlManager = session
.getAccessControlManager();
@@ -241,21 +242,24 @@ public static void deleteAllEntriesForAuthorizableFromACL(final Session session,
accessControlManager, path);
if (acl == null) {
// do nothing, if there is no content node at the given path
- return;
+ return 0;
}
// get ACEs of the node
final AccessControlEntry[] aces = acl.getAccessControlEntries();
+ int countRemoved = 0;
// loop thorough ACEs and find the one of the given principal
for (final AccessControlEntry ace : aces) {
final JackrabbitAccessControlEntry jace = (JackrabbitAccessControlEntry) ace;
- if (StringUtils.equals(jace.getPrincipal().getName(),
- authorizableID)) {
+
+ if (ArrayUtils.contains(authorizableIds, jace.getPrincipal().getName())) {
acl.removeAccessControlEntry(jace);
// bind new policy
accessControlManager.setPolicy(path, acl);
+ countRemoved++;
}
}
+ return countRemoved;
}
/** Retrieves JackrabbitAccessControlList for path.
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/Constants.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/Constants.java
index b82a8e82..1a4ee85b 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/Constants.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/Constants.java
@@ -26,12 +26,15 @@ private Constants() {
public static final String OBSOLETE_AUTHORIZABLES_KEY = "obsolete_authorizables";
public static final Set VALID_CONFIG_SECTION_IDENTIFIERS = new HashSet(Arrays.asList(
- GLOBAL_CONFIGURATION_KEY,
- GROUP_CONFIGURATION_KEY,
- USER_CONFIGURATION_KEY,
+ GLOBAL_CONFIGURATION_KEY,
+ GROUP_CONFIGURATION_KEY,
+ USER_CONFIGURATION_KEY,
ACE_CONFIGURATION_KEY,
OBSOLETE_AUTHORIZABLES_KEY));
public static final String USER_ANONYMOUS = "anonymous";
+ public static final String GROUPS_ROOT = "/home/groups";
+ public static final String USERS_ROOT = "/home/users";
+
}
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installationhistory/impl/AcHistoryServiceImpl.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installationhistory/impl/AcHistoryServiceImpl.java
index 9a08eaab..dcf23b3f 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installationhistory/impl/AcHistoryServiceImpl.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installationhistory/impl/AcHistoryServiceImpl.java
@@ -65,6 +65,14 @@ public void activate(@SuppressWarnings("rawtypes") final Map properties)
@Override
public void persistHistory(AcInstallationHistoryPojo history) {
+
+ if (nrOfSavedHistories == 0) {
+ String message = "History hasn't been persisted, configured number of histories is " + nrOfSavedHistories;
+ history.addVerboseMessage(message);
+ LOG.info(message);
+ return;
+ }
+
Session session = null;
try {
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installationhistory/impl/HistoryUtils.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installationhistory/impl/HistoryUtils.java
index dc524b6c..e7cee9bd 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installationhistory/impl/HistoryUtils.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installationhistory/impl/HistoryUtils.java
@@ -78,7 +78,7 @@ public static Node persistHistory(final Session session,
if (StringUtils.isNotBlank(history.getCrxPackageName())) {
name += "_via_" + history.getCrxPackageName();
} else {
- name += "_via_jmx";
+ name += "_via_api";
}
Node newHistoryNode = safeGetNode(acHistoryRootNode, name, NODETYPE_NT_UNSTRUCTURED);
@@ -119,8 +119,15 @@ public static void setHistoryNodeProperties(final Node historyNode,
historyNode.setProperty(PROPERTY_SUCCESS, history.isSuccess());
historyNode.setProperty(PROPERTY_EXECUTION_TIME,
history.getExecutionTime());
- historyNode.setProperty(PROPERTY_MESSAGES,
- history.getVerboseMessageHistory());
+
+ String messageHistory = history.getVerboseMessageHistory();
+
+ // 16777216 bytes = ~ 16MB was the error in #145, assuming chars*2, hence 16777216 / 2 = 8MB, using 7MB to consider the BSON
+ // overhead
+ if (messageHistory.length() > (7 * 1024 * 1024)) {
+ messageHistory = history.getMessageHistory(); // just use non-verbose history for this case
+ }
+ historyNode.setProperty(PROPERTY_MESSAGES, messageHistory);
historyNode.setProperty(PROPERTY_TIMESTAMP, history
.getInstallationDate().getTime());
historyNode.setProperty(PROPERTY_SLING_RESOURCE_TYPE,
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHook.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHook.java
index 80f48a29..aa222fcd 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHook.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHook.java
@@ -58,7 +58,7 @@ public void execute(InstallContext context) throws PackageException {
AcInstallationHistoryPojo history;
try {
history = acService.installYamlFilesFromPackage(context
- .getPackage().getArchive(), context.getSession());
+ .getPackage().getArchive());
} catch (Exception e) {
log("Exception while installing configurations: " + e,
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHookService.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHookService.java
index 22efd52e..568ad251 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHookService.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHookService.java
@@ -8,15 +8,13 @@
*/
package biz.netcentric.cq.tools.actool.installhook;
-import javax.jcr.Session;
-
import org.apache.jackrabbit.vault.fs.io.Archive;
import biz.netcentric.cq.tools.actool.installationhistory.AcInstallationHistoryPojo;
public interface AcToolInstallHookService {
- public AcInstallationHistoryPojo installYamlFilesFromPackage(Archive archive, Session session)
+ public AcInstallationHistoryPojo installYamlFilesFromPackage(Archive archive)
throws Exception;
}
\ No newline at end of file
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHookServiceImpl.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHookServiceImpl.java
index 7b64261f..91e2d691 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHookServiceImpl.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHookServiceImpl.java
@@ -13,8 +13,6 @@
import java.util.Properties;
import java.util.Set;
-import javax.jcr.Session;
-
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
@@ -40,14 +38,15 @@ public class AcToolInstallHookServiceImpl implements AcToolInstallHookService {
private ConfigFilesRetriever configFilesRetriever;
@Override
- public AcInstallationHistoryPojo installYamlFilesFromPackage(Archive archive, Session session)
+ public AcInstallationHistoryPojo installYamlFilesFromPackage(Archive archive)
throws Exception {
AcInstallationHistoryPojo history = new AcInstallationHistoryPojo();
Set authorizableInstallationHistorySet = new LinkedHashSet();
Map configs = configFilesRetriever.getConfigFileContentFromPackage(archive);
history.setCrxPackageName(getArchiveName(archive));
- aceService.installConfigurationFiles(session, history, configs, authorizableInstallationHistorySet);
+ String[] restrictedToPaths = null; // never use path restriction for hook usage for now
+ aceService.installConfigurationFiles(history, configs, authorizableInstallationHistorySet, restrictedToPaths);
return history;
}
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/exceptions/InvalidIntermediatePathException.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/exceptions/InvalidIntermediatePathException.java
new file mode 100644
index 00000000..342222e9
--- /dev/null
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/exceptions/InvalidIntermediatePathException.java
@@ -0,0 +1,10 @@
+package biz.netcentric.cq.tools.actool.validators.exceptions;
+
+public class InvalidIntermediatePathException extends
+ AcConfigBeanValidationException {
+
+ public InvalidIntermediatePathException(String message) {
+ super(message);
+ }
+
+}
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/impl/AuthorizableValidatorImpl.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/impl/AuthorizableValidatorImpl.java
index 52e5c0b8..497dfa9e 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/impl/AuthorizableValidatorImpl.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/impl/AuthorizableValidatorImpl.java
@@ -18,6 +18,7 @@
import biz.netcentric.cq.tools.actool.validators.exceptions.AcConfigBeanValidationException;
import biz.netcentric.cq.tools.actool.validators.exceptions.InvalidAuthorizableException;
import biz.netcentric.cq.tools.actool.validators.exceptions.InvalidGroupNameException;
+import biz.netcentric.cq.tools.actool.validators.exceptions.InvalidIntermediatePathException;
public class AuthorizableValidatorImpl implements AuthorizableValidator {
@@ -25,10 +26,15 @@ public class AuthorizableValidatorImpl implements AuthorizableValidator {
.getLogger(AuthorizableValidatorImpl.class);
private boolean enabled = true;
AuthorizableConfigBean authorizableConfigBean;
+ final String groupsPath;
+ final String usersPath;
- public AuthorizableValidatorImpl() {
+ public AuthorizableValidatorImpl(final String groupsPath, final String usersPath) {
+ this.groupsPath = groupsPath;
+ this.usersPath = usersPath;
}
+ @Override
public void validate(final AuthorizableConfigBean authorizableConfigBean)
throws AcConfigBeanValidationException {
this.authorizableConfigBean = authorizableConfigBean;
@@ -37,10 +43,49 @@ public void validate(final AuthorizableConfigBean authorizableConfigBean)
private boolean validate() throws AcConfigBeanValidationException {
if (enabled) {
- return validateAuthorizableProperties(this.authorizableConfigBean)
- && validateMemberOf(this.authorizableConfigBean)
- && validateMembers(this.authorizableConfigBean)
- && validateAuthorizableId(this.authorizableConfigBean);
+ return validateAuthorizableProperties(authorizableConfigBean)
+ && validateMemberOf(authorizableConfigBean)
+ && validateMembers(authorizableConfigBean)
+ && validateAuthorizableId(authorizableConfigBean)
+ && validateIntermediatePath(authorizableConfigBean);
+ }
+ return true;
+ }
+
+ public boolean validateIntermediatePath(
+ final AuthorizableConfigBean tmpPrincipalConfigBean)
+ throws InvalidAuthorizableException, InvalidIntermediatePathException {
+ boolean isGroup = tmpPrincipalConfigBean.isGroup();
+ String intermediatePath = tmpPrincipalConfigBean.getPath();
+ String currentPrincipalID = tmpPrincipalConfigBean.getPrincipalID();
+ final String basicErrorMessage = "Validation error while validating intermediate path of authorizable: "
+ + currentPrincipalID;
+ // we only care about paths starting with a slash. if there is none, the path is assumed to be relative
+ if (intermediatePath.startsWith("/")) {
+ if (!intermediatePath.startsWith(groupsPath) && !intermediatePath.startsWith(usersPath)) {
+ String message = basicErrorMessage
+ + " - the intermediate path either has to be relative (not starting with '/') or has to start with the authorizable root!";
+ LOG.error(message);
+ throw new InvalidIntermediatePathException(message);
+ }
+
+ if (!isGroup && intermediatePath.startsWith(groupsPath)) {
+ String message = basicErrorMessage + " - the intermediate path for the user must not be the groups path: " + groupsPath;
+ LOG.error(message);
+ throw new InvalidIntermediatePathException(message);
+ }
+ if (isGroup && intermediatePath.startsWith(usersPath)) {
+ String message = basicErrorMessage + " - the intermediate path for the group must not be the users path: " + usersPath;
+ LOG.error(message);
+ throw new InvalidIntermediatePathException(message);
+ }
+ if (intermediatePath.equals(groupsPath) || intermediatePath.equals(usersPath) || intermediatePath.equals(groupsPath + "/")
+ || intermediatePath.equals(usersPath + "/")) {
+ String message = basicErrorMessage
+ + " - the intermediate path must not be equal to the authorizable root but has to specify a subfolder of it!";
+ LOG.error(message);
+ throw new InvalidIntermediatePathException(message);
+ }
}
return true;
}
@@ -80,12 +125,10 @@ public boolean validateAuthorizableProperties(
}
}
-
-
-
return true;
}
+ @Override
public boolean validateMemberOf(
final AuthorizableConfigBean tmpPrincipalConfigBean)
throws InvalidGroupNameException {
@@ -122,7 +165,7 @@ public boolean validateMemberOf(
public boolean validateMembers(
final AuthorizableConfigBean tmpPrincipalConfigBean)
- throws InvalidGroupNameException {
+ throws InvalidGroupNameException {
final String currentPrincipal = tmpPrincipalConfigBean.getPrincipalID();
final String currentEntryValue = tmpPrincipalConfigBean
.getMembersStringFromConfig();
@@ -154,16 +197,17 @@ public boolean validateMembers(
return true;
}
+ @Override
public boolean validateAuthorizableId(
final AuthorizableConfigBean tmpPrincipalConfigBean)
- throws InvalidGroupNameException {
+ throws InvalidGroupNameException {
final String currentPrincipal = tmpPrincipalConfigBean.getPrincipalID();
- if (Validators.isValidAuthorizableId((String) currentPrincipal)) {
- tmpPrincipalConfigBean.setPrincipalID((String) currentPrincipal);
+ if (Validators.isValidAuthorizableId(currentPrincipal)) {
+ tmpPrincipalConfigBean.setPrincipalID(currentPrincipal);
} else {
final String message = "Validation error while reading group data: invalid group name: "
- + (String) currentPrincipal;
+ + currentPrincipal;
LOG.error(message);
throw new InvalidGroupNameException(message);
@@ -178,7 +222,7 @@ public void setBean(final AuthorizableConfigBean authorizableConfigBean) {
@Override
public void disable() {
- this.enabled = false;
+ enabled = false;
}
diff --git a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/aceservice/impl/AceServiceImplTest.java b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/aceservice/impl/AceServiceImplTest.java
new file mode 100644
index 00000000..ca9ac218
--- /dev/null
+++ b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/aceservice/impl/AceServiceImplTest.java
@@ -0,0 +1,29 @@
+package biz.netcentric.cq.tools.actool.aceservice.impl;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class AceServiceImplTest {
+
+ @Test
+ public void testIsRelevantPath() {
+ AceServiceImpl aceServiceImpl = new AceServiceImpl();
+
+ String[] restrictedToPaths = new String[] { "/content/site1", "/content/site3" };
+ assertTrue(aceServiceImpl.isRelevantPath("/content/site1", restrictedToPaths));
+ assertFalse(aceServiceImpl.isRelevantPath("/content/site1ButNotSameRoot", restrictedToPaths));
+ assertTrue(aceServiceImpl.isRelevantPath("/content/site1/page", restrictedToPaths));
+
+ assertFalse(aceServiceImpl.isRelevantPath("/content/site2", restrictedToPaths));
+ assertFalse(aceServiceImpl.isRelevantPath("/content/site2/page", restrictedToPaths));
+
+ assertTrue(aceServiceImpl.isRelevantPath("/content/site3", restrictedToPaths));
+ assertTrue(aceServiceImpl.isRelevantPath("/content/site3/page", restrictedToPaths));
+
+ assertFalse(aceServiceImpl.isRelevantPath("/etc/cloudservices", restrictedToPaths));
+
+ }
+
+}
diff --git a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/comparators/AcePermissionComparatorTest.java b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/comparators/AcePermissionComparatorTest.java
new file mode 100644
index 00000000..de2b0b53
--- /dev/null
+++ b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/comparators/AcePermissionComparatorTest.java
@@ -0,0 +1,112 @@
+package biz.netcentric.cq.tools.actool.comparators;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.commons.lang.StringUtils;
+import org.junit.Test;
+
+import biz.netcentric.cq.tools.actool.configmodel.AceBean;
+
+public class AcePermissionComparatorTest {
+
+ @Test
+ public void testReorderingWithoutKeepOrder() {
+
+ // keep order if it is correct already
+ assertEquals("no1-no2-no3-no4", toComparableString(toAutoSortedSet(
+ getAceBean("no1", "deny", false),
+ getAceBean("no2", "deny", false),
+ getAceBean("no3", "allow", false),
+ getAceBean("no4", "allow", false))));
+
+ // only allows - order not changed
+ assertEquals("no1-no2-no3", toComparableString(toAutoSortedSet(
+ getAceBean("no1", "allow", false),
+ getAceBean("no2", "allow", false),
+ getAceBean("no3", "allow", false))));
+
+ // one allow many denies - order changed
+ assertEquals("no2-no3-no4-no1", toComparableString(toAutoSortedSet(
+ getAceBean("no1", "allow", false),
+ getAceBean("no2", "deny", false),
+ getAceBean("no3", "deny", false),
+ getAceBean("no4", "deny", false))));
+
+ // one deny reorder
+ assertEquals("no4-no1-no2-no3", toComparableString(toAutoSortedSet(
+ getAceBean("no1", "allow", false),
+ getAceBean("no2", "allow", false),
+ getAceBean("no3", "allow", false),
+ getAceBean("no4", "deny", false))));
+
+ // many mixed ones
+ assertEquals("no2-no4-no6-no8-no1-no3-no5-no7", toComparableString(toAutoSortedSet(
+ getAceBean("no1", "allow", false),
+ getAceBean("no2", "deny", false),
+ getAceBean("no3", "allow", false),
+ getAceBean("no4", "deny", false),
+ getAceBean("no5", "allow", false),
+ getAceBean("no6", "deny", false),
+ getAceBean("no7", "allow", false),
+ getAceBean("no8", "deny", false))));
+
+ }
+
+ @Test
+ public void testReorderingWithKeepOrder() {
+
+ // simple case - one order kept
+ assertEquals("no2-no3-no1-no4", toComparableString(toAutoSortedSet(
+ getAceBean("no1", "allow", false),
+ getAceBean("no2", "deny", false),
+ getAceBean("no3", "deny", false),
+ getAceBean("no4", "deny", true))));
+
+ // two item keep order
+ assertEquals("no3-no1-no2-no4", toComparableString(toAutoSortedSet(
+ getAceBean("no1", "allow", false),
+ getAceBean("no2", "deny", true),
+ getAceBean("no3", "deny", false),
+ getAceBean("no4", "deny", true))));
+
+ // all items keep order
+ assertEquals("no1-no2-no3-no4", toComparableString(toAutoSortedSet(
+ getAceBean("no1", "allow", true),
+ getAceBean("no2", "deny", true),
+ getAceBean("no3", "allow", true),
+ getAceBean("no4", "deny", true))));
+
+ }
+
+ private Set toAutoSortedSet(AceBean... beans) {
+
+ final Set orderedAceBeanSet = new TreeSet(new AcePermissionComparator());
+ orderedAceBeanSet.addAll(Arrays.asList(beans));
+ return orderedAceBeanSet;
+
+ }
+
+ private String toComparableString(Set beans) {
+ List ids = new ArrayList();
+ for (AceBean bean : beans) {
+ ids.add(bean.getPrincipalName());
+ }
+ return StringUtils.join(ids, "-");
+
+ }
+
+ private AceBean getAceBean(String id, String permission, boolean keepOrder) {
+ AceBean aceBean = new AceBean();
+ aceBean.setPrincipal(id);
+ aceBean.setPermission(permission);
+ aceBean.setKeepOrder(keepOrder);
+ return aceBean;
+ }
+
+}
diff --git a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMergerTest.java b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMergerTest.java
index 5d6a092e..c2b7dff0 100644
--- a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMergerTest.java
+++ b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMergerTest.java
@@ -28,7 +28,7 @@
import biz.netcentric.cq.tools.actool.validators.impl.ObsoleteAuthorizablesValidatorImpl;
/** Tests the YamlConfigurationMerger
- *
+ *
* @author Roland Gruber */
public class YamlConfigurationMergerTest {
@@ -53,8 +53,8 @@ public void testMemberGroups() throws IOException, RepositoryException, AcConfig
assertEquals(3, groupA.getMemberOf().length);
final AuthorizableConfigBean groupB = groups.get("groupB").iterator().next();
assertEquals(2, groupB.getMemberOf().length);
- final AuthorizableConfigBean groupC = groups.get("groupC").iterator().next();
- final AuthorizableConfigBean groupD = groups.get("groupD").iterator().next();
+ groups.get("groupC").iterator().next();
+ groups.get("groupD").iterator().next();
}
}
diff --git a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/BeanValidatorsTest.java b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/BeanValidatorsTest.java
index 8098365a..da743128 100644
--- a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/BeanValidatorsTest.java
+++ b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/BeanValidatorsTest.java
@@ -42,7 +42,6 @@
import biz.netcentric.cq.tools.actool.validators.impl.AceBeanValidatorImpl;
import biz.netcentric.cq.tools.actool.validators.impl.AuthorizableValidatorImpl;
-
public class BeanValidatorsTest {
@Mock
@@ -60,7 +59,6 @@ public class BeanValidatorsTest {
@InjectMocks
ConfigReader yamlConfigReader = new YamlConfigReader();
-
List aclList;
Set groupsFromConfig;
List aceBeanList = new ArrayList();
@@ -68,32 +66,33 @@ public class BeanValidatorsTest {
@Before
public void setup() throws IOException, RepositoryException,
- AcConfigBeanValidationException {
+ AcConfigBeanValidationException {
initMocks(this);
doReturn(session).when(repository).loginAdministrative(null);
accessControlPolicy = mock(AccessControlList.class,
withSettings().extraInterfaces(JackrabbitAccessControlList.class));
- doReturn(new String[]{"rep:glob"}).when((JackrabbitAccessControlList)accessControlPolicy).getRestrictionNames();
+ doReturn(new String[] { "rep:glob" }).when((JackrabbitAccessControlList) accessControlPolicy).getRestrictionNames();
doReturn(accessControlManager).when(session).getAccessControlManager();
- doReturn(new AccessControlPolicy[]{accessControlPolicy}).when(accessControlManager).getPolicies("/");
+ doReturn(new AccessControlPolicy[] { accessControlPolicy }).when(accessControlManager).getPolicies("/");
doThrow(new RepositoryException("invalid permission")).when(accessControlManager).privilegeFromName("read");
doThrow(new RepositoryException("invalid permission")).when(accessControlManager).privilegeFromName("jcr_all");
final List yamlList = ValidatorTestHelper.getYamlList("testconfig.yaml");
- final AuthorizableValidator authorizableValidator = new AuthorizableValidatorImpl();
+ final AuthorizableValidator authorizableValidator = new AuthorizableValidatorImpl("/home/groups", "/home/users");
authorizableValidator.disable();
groupsFromConfig = yamlConfigReader.getGroupConfigurationBeans(
yamlList, authorizableValidator).keySet();
+
ValidatorTestHelper.createAuthorizableTestBeans(yamlList, yamlConfigReader, authorizableBeanList);
ValidatorTestHelper.createAceTestBeans(yamlList, yamlConfigReader, groupsFromConfig, aceBeanList);
}
@Test
public void testAuthorizableBeans() {
- final AuthorizableValidator authorizableValidator = new AuthorizableValidatorImpl();
+ final AuthorizableValidator authorizableValidator = new AuthorizableValidatorImpl("/home/groups", "/home/users");
for (final AuthorizableConfigBean authorizableBean : authorizableBeanList) {
assertEquals(
ValidatorTestHelper.getSimpleValidationException(authorizableBean,
diff --git a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/RestrictionValidationTest.java b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/RestrictionValidationTest.java
index bed415fc..22c49593 100644
--- a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/RestrictionValidationTest.java
+++ b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/RestrictionValidationTest.java
@@ -33,11 +33,10 @@
import biz.netcentric.cq.tools.actool.validators.exceptions.AcConfigBeanValidationException;
import biz.netcentric.cq.tools.actool.validators.impl.AceBeanValidatorImpl;
import biz.netcentric.cq.tools.actool.validators.impl.AuthorizableValidatorImpl;
-/**
- * Contains unit tests checking support of different restrictions
- * @author jochenkoschorkej
- *
- */
+
+/** Contains unit tests checking support of different restrictions
+ *
+ * @author jochenkoschorkej */
public class RestrictionValidationTest {
@Mock
@@ -62,7 +61,7 @@ public class RestrictionValidationTest {
@Before
public void setup() throws IOException, RepositoryException,
- AcConfigBeanValidationException {
+ AcConfigBeanValidationException {
initMocks(this);
doReturn(session).when(repository).loginAdministrative(null);
@@ -71,7 +70,7 @@ public void setup() throws IOException, RepositoryException,
withSettings().extraInterfaces(JackrabbitAccessControlList.class));
doReturn(accessControlManager).when(session).getAccessControlManager();
- doReturn(new AccessControlPolicy[]{accessControlPolicy}).when(accessControlManager).getPolicies("/");
+ doReturn(new AccessControlPolicy[] { accessControlPolicy }).when(accessControlManager).getPolicies("/");
doThrow(new RepositoryException("invalid permission")).when(accessControlManager).privilegeFromName("read");
doThrow(new RepositoryException("invalid permission")).when(accessControlManager).privilegeFromName("jcr_all");
@@ -79,7 +78,7 @@ public void setup() throws IOException, RepositoryException,
private void setupBeansFromTestYaml(final String path) throws IOException, AcConfigBeanValidationException, RepositoryException {
final List yamlList = ValidatorTestHelper.getYamlList(path);
- final AuthorizableValidator authorizableValidator = new AuthorizableValidatorImpl();
+ final AuthorizableValidator authorizableValidator = new AuthorizableValidatorImpl("/home/groups", "/home/users");
authorizableValidator.disable();
groupsFromConfig = yamlConfigReader.getGroupConfigurationBeans(
yamlList, authorizableValidator).keySet();
@@ -89,7 +88,7 @@ private void setupBeansFromTestYaml(final String path) throws IOException, AcCon
@Test
public void testAceBeansOnlyRepGlobRestrictionSupported() throws IOException, AcConfigBeanValidationException, RepositoryException {
- doReturn(new String[]{"rep:glob"}).when((JackrabbitAccessControlList)accessControlPolicy).getRestrictionNames();
+ doReturn(new String[] { "rep:glob" }).when((JackrabbitAccessControlList) accessControlPolicy).getRestrictionNames();
setupBeansFromTestYaml("testRestrictionsConfigs/test-restrictions1.yaml");
testExceptions();
}
@@ -97,14 +96,15 @@ public void testAceBeansOnlyRepGlobRestrictionSupported() throws IOException, Ac
@Test
public void testAceBeansOnlyNtNamesRestrictionSupported() throws IOException, AcConfigBeanValidationException, RepositoryException {
setupBeansFromTestYaml("testRestrictionsConfigs/test-restrictions2.yaml");
- doReturn(new String[]{"rep:ntNames"}).when((JackrabbitAccessControlList)accessControlPolicy).getRestrictionNames();
+ doReturn(new String[] { "rep:ntNames" }).when((JackrabbitAccessControlList) accessControlPolicy).getRestrictionNames();
testExceptions();
}
@Test
public void testAceBeansAllRestrictionsSupported() throws IOException, AcConfigBeanValidationException, RepositoryException {
setupBeansFromTestYaml("testRestrictionsConfigs/test-restrictions3.yaml");
- doReturn(new String[]{"rep:ntNames", "rep:glob", "rep:prefixes"}).when((JackrabbitAccessControlList)accessControlPolicy).getRestrictionNames();
+ doReturn(new String[] { "rep:ntNames", "rep:glob", "rep:prefixes" }).when((JackrabbitAccessControlList) accessControlPolicy)
+ .getRestrictionNames();
testExceptions();
}
diff --git a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/ValidatorTestHelper.java b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/ValidatorTestHelper.java
index a0d1a0b5..35ebb7fa 100644
--- a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/ValidatorTestHelper.java
+++ b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/ValidatorTestHelper.java
@@ -21,26 +21,34 @@
import biz.netcentric.cq.tools.actool.validators.exceptions.AcConfigBeanValidationException;
import biz.netcentric.cq.tools.actool.validators.impl.AceBeanValidatorImpl;
import biz.netcentric.cq.tools.actool.validators.impl.AuthorizableValidatorImpl;
-/**
- * Helper class containing static methods used in validator-related unit tests based on test yaml files
- * @author jochenkoschorkej
+
+/** Helper class containing static methods used in validator-related unit tests based on test yaml files
*
- */
+ * @author jochenkoschorkej */
public class ValidatorTestHelper {
- private ValidatorTestHelper(){}
+ private ValidatorTestHelper() {
+ }
- static void createAuthorizableTestBeans(final List yamlList, ConfigReader yamlConfigReader, List authorizableBeanList)
- throws AcConfigBeanValidationException {
- final AuthorizableValidator authorizableValidator = new AuthorizableValidatorImpl();
+ static void createAuthorizableTestBeans(final List yamlList, ConfigReader yamlConfigReader,
+ List authorizableBeanList)
+ throws AcConfigBeanValidationException {
+ final AuthorizableValidator authorizableValidator = new AuthorizableValidatorImpl("/home/groups", "/home/users");
authorizableValidator.disable();
- final Map> authorizablesMap = yamlConfigReader
+ final Map> groupsMap = yamlConfigReader
.getGroupConfigurationBeans(yamlList, authorizableValidator);
- for (final Entry> authorizableEntrySet : authorizablesMap
+ final Map> usersMap = yamlConfigReader
+ .getUserConfigurationBeans(yamlList, authorizableValidator);
+ for (final Entry> authorizableEntrySet : groupsMap
+ .entrySet()) {
+ authorizableBeanList.addAll(authorizableEntrySet.getValue());
+ }
+ for (final Entry> authorizableEntrySet : usersMap
.entrySet()) {
authorizableBeanList.addAll(authorizableEntrySet.getValue());
}
}
+
static String getTestConfigAsString(final String resourceName)
throws IOException {
final ClassLoader classloader = Thread.currentThread()
@@ -52,8 +60,9 @@ static String getTestConfigAsString(final String resourceName)
return stringWriter.toString();
}
- static void createAceTestBeans(final List yamlList, ConfigReader yamlConfigReader, Set groupsFromConfig, List aceBeanList)
- throws RepositoryException, AcConfigBeanValidationException {
+ static void createAceTestBeans(final List yamlList, ConfigReader yamlConfigReader, Set groupsFromConfig,
+ List aceBeanList)
+ throws RepositoryException, AcConfigBeanValidationException {
final AceBeanValidator aceBeanValidator = new AceBeanValidatorImpl(
groupsFromConfig);
diff --git a/accesscontroltool-bundle/src/test/resources/testconfig.yaml b/accesscontroltool-bundle/src/test/resources/testconfig.yaml
index 7c10e10a..75e35183 100644
--- a/accesscontroltool-bundle/src/test/resources/testconfig.yaml
+++ b/accesscontroltool-bundle/src/test/resources/testconfig.yaml
@@ -32,22 +32,107 @@
- group_D:
+ - isMemberOf: group_B
+ path: /home/groups/g
+
+ - group_E:
+
- isMemberOf:
+ path: relativePath
- - group_C:
+ - group_F:
- - isMemberOf: group_B
- path: /home/groups/g
+ - isMemberOf:
+
+
+ - group_G:
+
+ - isMemberOf:
+ path: /home/groups
+ assertedException: InvalidIntermediatePathException
+
+
+ - group_I:
+
+ - isMemberOf:
+ path: /home/group
+ assertedException: InvalidIntermediatePathException
+ - group_K:
+
+ - isMemberOf:
+ path: /home
+ assertedException: InvalidIntermediatePathException
+
+ - group_L:
+
+ - isMemberOf:
+ path: /
+ assertedException: InvalidIntermediatePathException
+
+ - group_M:
+
+ - isMemberOf:
+ path: /home/users/m
+ assertedException: InvalidIntermediatePathException
+
+ - group_N:
+
+ - isMemberOf:
+ path: /home/groups/
+ assertedException: InvalidIntermediatePathException
# invalid isMemberOf-name name
- - group_F:
+ - group_O:
- isMemberOf: group_Ö
path: /home/groups/g
assertedException: InvalidGroupNameException
+- user_config:
+
+ - user_A:
+
+ - isMemberOf:
+ path: /home/groups
+ password: secret
+ assertedException: InvalidIntermediatePathException
+
+ - user_B:
+
+ - isMemberOf:
+ path: /home/users
+ password: secret
+ assertedException: InvalidIntermediatePathException
+
+ - user_C:
+
+ - isMemberOf:
+ path: /home/user
+ password: secret
+ assertedException: InvalidIntermediatePathException
+
+ - user_D:
+
+ - isMemberOf:
+ path: /home/groups/u
+ password: secret
+ assertedException: InvalidIntermediatePathException
+
+ - user_E:
+
+ - isMemberOf:
+ path: /home/users/u
+ assertedException: InvalidAuthorizableException
+
+ - user_F:
+
+ - isMemberOf:
+ path: /home/users/
+ assertedException: InvalidAuthorizableException
+
+
- ace_config:
diff --git a/accesscontroltool-exampleconfig-package/pom.xml b/accesscontroltool-exampleconfig-package/pom.xml
index 35f7b855..827afcae 100644
--- a/accesscontroltool-exampleconfig-package/pom.xml
+++ b/accesscontroltool-exampleconfig-package/pom.xml
@@ -15,7 +15,7 @@
biz.netcentric.cq.tools.accesscontroltool
accesscontroltool
- 1.9.1
+ 1.9.2
diff --git a/accesscontroltool-oakindex-package/pom.xml b/accesscontroltool-oakindex-package/pom.xml
index 865b0244..e7d6be4b 100644
--- a/accesscontroltool-oakindex-package/pom.xml
+++ b/accesscontroltool-oakindex-package/pom.xml
@@ -15,7 +15,7 @@
biz.netcentric.cq.tools.accesscontroltool
accesscontroltool
- 1.9.1
+ 1.9.2
diff --git a/accesscontroltool-package/pom.xml b/accesscontroltool-package/pom.xml
index 4934eb68..6e770252 100644
--- a/accesscontroltool-package/pom.xml
+++ b/accesscontroltool-package/pom.xml
@@ -15,7 +15,7 @@
biz.netcentric.cq.tools.accesscontroltool
accesscontroltool
- 1.9.1
+ 1.9.2
diff --git a/docs/AdvancedFeatures.md b/docs/AdvancedFeatures.md
index 53522205..bd1260c8 100644
--- a/docs/AdvancedFeatures.md
+++ b/docs/AdvancedFeatures.md
@@ -137,7 +137,7 @@ Expressions are evaluated using javax.el expression language. The following util
## Configure permissions for anonymous (since 1.8.2)
-Normally it is ensured by validation that a configuration's group system is self-contained - this means out-of-the-box groups like ```contributor``` cannot be used. For registered users in the system this approach works well since either the users are manually assigned to groups (by a user admin) or the membership relationship is maintained by LDAP or SSO extensions. For the ```anonymous``` user on publish that is not logged in by definition, there is no hook that allows to assign it to a group in the AC Tools configuration. Therefore as an exception, it is allowed to use the user ```anonymous``` in the ```members``` attribute of a group configuration.
+Normally it is ensured by validation that a configuration's group system is self-contained - this means out-of-the-box groups like `contributor` cannot be used. For registered users in the system this approach works well since either the users are manually assigned to groups (by a user admin) or the membership relationship is maintained by LDAP or SSO extensions. For the `anonymous` user on publish that is not logged in by definition, there is no hook that allows to assign it to a group in the AC Tools configuration. Therefore as an exception, it is allowed to use the user `anonymous` in the `members` attribute of a group configuration.
## Configure memberships to Dynamic Groups
@@ -192,3 +192,10 @@ The following examples shows a legitimate example of using `keepOrder: true`:
sling:resourceTypes: myproj/iframe
```
This example gives the group `myproj-editor` edit rights for all content in folder `myproj`, except for the iframe component.
+
+## Intermediate save() calls during ACL installation
+
+For large installations (> 1000 groups) that use MongoDB, the system possibly may get into an invalid state as older versions of OAK (AEM 6.1/6.2 ootb) do not always correctly fire the post commit hook for very large change sets (OAK-5557). To circumvent this issue it is possible since v1.9.2 to configure the OSGi property `intermediateSaves=true` of PID `biz.netcentric.cq.tools.actool.aceservice.impl.AceServiceImpl`.
+
+NOTE: This is never necessary when using TarMK and also it should only be used for MongoMK for large installations that do not contain a fix for OAK-5557 yet as the rollback functionality is lost when enabling intermediate saves.
+
diff --git a/docs/ApplyConfig.md b/docs/ApplyConfig.md
index 932d50aa..4a8251a9 100644
--- a/docs/ApplyConfig.md
+++ b/docs/ApplyConfig.md
@@ -28,9 +28,9 @@ If you use the content-package-maven-plugin enable the installation hook via:
```
-The ```*.yaml``` files are installed directly from the package content and respect the [run mode semantics](Configuration.md).
+The `*.yaml` files are installed directly from the package content and respect the [run mode semantics](Configuration.md). Otherwise there is no limitation, so the YAML files will be picked up from anywhere in the package (as long as the parent node does not contain a `.` followed by one or multiple not matching run modes).
-Although it is not necessary that the YAML files are covered by the filter rules of the ```filter.xml```, this is recommended practice. That way you can see afterwards in the repository which YAML files have been processed. However if you would not let the ```filter.xml``` cover your YAML files, those files would still be processed by the installation hook.
+Although it is not necessary that the YAML files are covered by the filter rules of the `filter.xml`, this is recommended practice. That way you can see afterwards in the repository which YAML files have been processed. However if you would not let the `filter.xml` cover your YAML files, those files would still be processed by the installation hook.
## JMX
diff --git a/docs/Configuration.md b/docs/Configuration.md
index 6f5c9507..577fdd2d 100644
--- a/docs/Configuration.md
+++ b/docs/Configuration.md
@@ -107,7 +107,7 @@ Group memberships can be set on user entry or group entry or both.
## Configuration of ACEs
-The configurations are done per principal followed by indented settings for each ACE. This data includes
+The configurations are done per principal (currently on group ids are supported due to [issue #141](https://github.com/Netcentric/accesscontroltool/issues/141)) followed by indented settings for each ACE. This data includes
property | comment | required
--- | --- | ---
diff --git a/docs/Jmx.md b/docs/Jmx.md
index 53be4a2c..96a602b7 100644
--- a/docs/Jmx.md
+++ b/docs/Jmx.md
@@ -29,10 +29,10 @@ The path of the config files is configured in OSGi - AC Installation Service.
-### pathBasedDump() and groupBasedDump()
+### groupBasedDump() and pathBasedDump()
-* path based dumps: here all ACEs in the dump are grouped by path thus representing a complete ACL. This kind of dump gets triggered by the method: pathBasedDump().
-* group based dumps: here all ACEs in the dump are grouped by their respective principal (group or user). This kind of dump gets triggered by the method: groupBasedDump().
+* Group based dump: here all ACEs in the dump are grouped by their respective principal (group or user). This kind of dump gets triggered by the method: groupBasedDump(). The result is in AC Tool config file format and can be used as template to create a configuration file.
+* Path based dump: here all ACEs in the dump are grouped by path thus representing a complete ACL. This kind of dump gets triggered by the method: pathBasedDump().
The created dump can be watched directly in JMX and also gets saved in CRX under /var/statistics/achistory/dump_[Timestamp]. The number of dumps to be saved in CRX can be configured in the OSGi configuration of the dump service in the field: "Number of dumps to save" (see screenshot).
diff --git a/docs/Migration.md b/docs/Migration.md
index 4f59dc3e..60ff08b1 100644
--- a/docs/Migration.md
+++ b/docs/Migration.md
@@ -9,7 +9,7 @@ Please note that for CQ 5.6 you will need version 1.8.5 of the tool.
## 2. Export rules
-Do an export using groupBasedDump() on [JMX interface](Jmx.md). The dump will provide you a Yaml export with all AC entries in your system. Save it to a file and remove all entries that should not be managed by AC Tool. E.g. you do not want to manage the system groups such as "everyone" and "administrators".
+Do an export using **groupBasedDump()** on [JMX interface](Jmx.md). The dump will provide you a Yaml export with all AC entries in your system. Save it to a file and remove all entries that should not be managed by AC Tool. E.g. you do not want to manage the system groups such as "everyone" and "administrators".
## 3. Add rules to your content package
diff --git a/pom.xml b/pom.xml
index 89d13bc6..ed9889a6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
biz.netcentric.cq.tools.accesscontroltool
accesscontroltool
- 1.9.1
+ 1.9.2
pom
Access Control Tool - Reactor Project