/*
* (C) Copyright 2015 Netcentric AG.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package biz.netcentric.cq.tools.actool.impl;
import static biz.netcentric.cq.tools.actool.history.AcInstallationLog.msHumanReadable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
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.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.ValueFormatException;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.StopWatch;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.cm.ConfigurationAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import biz.netcentric.cq.tools.actool.aceinstaller.AceBeanInstaller;
import biz.netcentric.cq.tools.actool.aceservice.AceService;
import biz.netcentric.cq.tools.actool.api.AcInstallationService;
import biz.netcentric.cq.tools.actool.api.InstallationLog;
import biz.netcentric.cq.tools.actool.authorizableinstaller.AuthorizableCreatorException;
import biz.netcentric.cq.tools.actool.authorizableinstaller.AuthorizableInstallerService;
import biz.netcentric.cq.tools.actool.configmodel.AcConfiguration;
import biz.netcentric.cq.tools.actool.configmodel.AceBean;
import biz.netcentric.cq.tools.actool.configmodel.AcesConfig;
import biz.netcentric.cq.tools.actool.configmodel.AuthorizableConfigBean;
import biz.netcentric.cq.tools.actool.configmodel.AuthorizablesConfig;
import biz.netcentric.cq.tools.actool.configreader.ConfigFilesRetriever;
import biz.netcentric.cq.tools.actool.configreader.ConfigReader;
import biz.netcentric.cq.tools.actool.configreader.ConfigurationMerger;
import biz.netcentric.cq.tools.actool.dumpservice.ConfigDumpService;
import biz.netcentric.cq.tools.actool.helper.AcHelper;
import biz.netcentric.cq.tools.actool.helper.AccessControlUtils;
import biz.netcentric.cq.tools.actool.helper.AclBean;
import biz.netcentric.cq.tools.actool.helper.Constants;
import biz.netcentric.cq.tools.actool.helper.PurgeHelper;
import biz.netcentric.cq.tools.actool.helper.QueryHelper;
import biz.netcentric.cq.tools.actool.history.AcHistoryService;
import biz.netcentric.cq.tools.actool.history.AcInstallationLog;
import biz.netcentric.cq.tools.actool.installationhistory.AcInstallationHistoryPojo;
@Service
@Component(metatype = true, label = "AC Installation Service", description = "Service that installs groups & ACEs according to textual configuration files")
public class AcInstallationServiceImpl implements AcInstallationService, AcInstallationServiceInternal, AceService {
private static final Logger LOG = LoggerFactory.getLogger(AcInstallationServiceImpl.class);
private static final String LEGACY_CONFIG_PID = "biz.netcentric.cq.tools.actool.aceservice.impl.AceServiceImpl";
static final String PROPERTY_CONFIGURATION_PATH = "AceService.configurationPath";
static final String PROPERTY_INTERMEDIATE_SAVES = "intermediateSaves";
@Reference
AuthorizableInstallerService authorizableCreatorService;
@Reference(target = "(component.name=biz.netcentric.cq.tools.actool.aceinstaller.AceBeanInstallerClassic)")
AceBeanInstaller aceBeanInstallerClassic;
@Reference(target = "(component.name=biz.netcentric.cq.tools.actool.aceinstaller.AceBeanInstallerIncremental)")
AceBeanInstaller aceBeanInstallerIncremental;
@Reference
private SlingRepository repository;
@Reference
AcHistoryService acHistoryService;
@Reference
private ConfigDumpService dumpservice;
@Reference
private ConfigReader configReader;
@Reference
private ConfigurationMerger configurationMerger;
@Reference
private ConfigFilesRetriever configFilesRetriever;
@Reference
private ConfigurationAdmin configAdmin;
@Property(label = "Configuration storage path", description = "CRX path where ACE configuration gets stored", name = AcInstallationServiceImpl.PROPERTY_CONFIGURATION_PATH, value = "")
private String configuredAcConfigurationRootPath;
@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 = AcInstallationServiceImpl.PROPERTY_INTERMEDIATE_SAVES, value = "")
private boolean intermediateSaves;
@Activate
public void activate(Map<String, Object> properties) throws Exception {
Dictionary<String, Object> legacyProps = configAdmin.getConfiguration(LEGACY_CONFIG_PID).getProperties();
if (legacyProps != null) {
properties = new HashMap<String, Object>(properties);
Enumeration<String> keysEnum = legacyProps.keys();
while (keysEnum.hasMoreElements()) {
String key = keysEnum.nextElement();
properties.put(key, legacyProps.get(key));
}
}
LOG.debug("Activated AceService!");
configuredAcConfigurationRootPath = PropertiesUtil.toString(properties.get(PROPERTY_CONFIGURATION_PATH), "");
LOG.info("Conifg " + PROPERTY_CONFIGURATION_PATH + "=" + configuredAcConfigurationRootPath);
intermediateSaves = PropertiesUtil.toBoolean(properties.get(PROPERTY_INTERMEDIATE_SAVES), false);
LOG.info("Conifg " + PROPERTY_INTERMEDIATE_SAVES + "=" + intermediateSaves);
}
@Override
public InstallationLog apply() {
return apply(getConfiguredAcConfigurationRootPath(), null);
}
@Override
public InstallationLog apply(String configurationRootPath) {
return apply(configurationRootPath, null);
}
@Override
public InstallationLog apply(String[] restrictedToPaths) {
return apply(getConfiguredAcConfigurationRootPath(), restrictedToPaths);
}
@Override
public InstallationLog apply(String configurationRootPath, String[] restrictedToPaths) {
AcInstallationLog installLog = new AcInstallationLog();
Session session = null;
try {
session = repository.loginService(Constants.USER_AC_SERVICE, null);
Map<String, String> newestConfigurations = configFilesRetriever.getConfigFileContentFromNode(configurationRootPath, session);
installConfigurationFiles(installLog, newestConfigurations, restrictedToPaths, session);
} catch (AuthorizableCreatorException e) {
// exception was added to history in installConfigurationFiles() before it was saved
LOG.warn("Exception during installation of authorizables (no rollback), e=" + e, e);
// 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);
// exception was added to history in installConfigurationFiles() before it was saved
} finally {
if (session != null) {
session.logout();
}
}
return installLog;
}
/** Common entry point for JMX and install hook. */
@Override
public void installConfigurationFiles(AcInstallationLog installLog, Map<String, String> configurationFileContentsByFilename,
String[] restrictedToPaths, Session session)
throws Exception {
String origThreadName = Thread.currentThread().getName();
try {
Thread.currentThread().setName(origThreadName + "-ACTool-Config-Worker");
StopWatch sw = new StopWatch();
sw.start();
installLog.addMessage(LOG, "*** Applying AC Tool Configuration using v" + getVersion() + "... ");
if (configurationFileContentsByFilename != null) {
installLog.setConfigFileContentsByName(configurationFileContentsByFilename);
AcConfiguration acConfiguration = configurationMerger.getMergedConfigurations(configurationFileContentsByFilename, installLog,
configReader, session);
installLog.setAcConfiguration(acConfiguration);
installMergedConfigurations(installLog, acConfiguration, restrictedToPaths, session);
removeObsoleteAuthorizables(installLog, acConfiguration.getObsoleteAuthorizables(), session);
}
sw.stop();
long executionTime = sw.getTime();
LOG.info("Successfully applied AC Tool configuration in " + msHumanReadable(executionTime));
installLog.setExecutionTime(executionTime);
} catch (Exception e) {
installLog.addError(e.toString()); // ensure exception is added to installLog 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(installLog);
} catch (Exception e) {
LOG.warn("Could not persist history, e=" + e, e);
}
Thread.currentThread().setName(origThreadName);
}
}
private void installAcConfiguration(
AcConfiguration acConfiguration, AcInstallationLog installLog,
Map<String, Set<AceBean>> repositoryDumpAceMap, String[] restrictedToPaths, Session session) throws Exception {
if (acConfiguration.getAceConfig() == null) {
String message = "ACE config not found in YAML file! installation aborted!";
LOG.error(message);
throw new IllegalArgumentException(message);
}
installAuthorizables(installLog, acConfiguration.getAuthorizablesConfig(), session);
installAces(installLog, acConfiguration, repositoryDumpAceMap, restrictedToPaths, session);
}
private void removeAcesForPathsNotInConfig(AcInstallationLog installLog, Session session, Set<String> principalsInConfig,
Map<String, Set<AceBean>> repositoryDumpAceMap, AcesConfig aceBeansFromConfig)
throws UnsupportedRepositoryOperationException, RepositoryException {
int countAcesCleaned = 0;
int countPathsCleaned = 0;
Set<String> relevantPathsForCleanup = getRelevantPathsForAceCleanup(principalsInConfig, repositoryDumpAceMap,
aceBeansFromConfig);
for (String relevantPath : relevantPathsForCleanup) {
// delete ACE if principal *is* in config, but the path *is not* in config
int countRemoved = AccessControlUtils.deleteAllEntriesForPrincipalsFromACL(session,
relevantPath, principalsInConfig.toArray(new String[principalsInConfig.size()]));
installLog.addMessage(LOG, "Cleaned (deleted) " + countRemoved + " ACEs of path " + relevantPath
+ " from all ACEs for configured authorizables");
if (countRemoved > 0) {
countPathsCleaned++;
}
countAcesCleaned += countRemoved;
}
if (countAcesCleaned > 0) {
installLog.addMessage(LOG, "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)");
}
}
private Set<String> getRelevantPathsForAceCleanup(Set<String> authorizablesInConfig, Map<String, Set<AceBean>> repositoryDumpAceMap,
AcesConfig aceBeansFromConfig) {
// loop through all ACLs found in the repository
Set<String> relevantPathsForCleanup = new HashSet<String>();
for (Map.Entry<String, Set<AceBean>> entry : repositoryDumpAceMap.entrySet()) {
Set<AceBean> existingAcl = entry.getValue();
for (AceBean existingAceFromDump : existingAcl) {
String jcrPath = existingAceFromDump.getJcrPath();
String principalName = existingAceFromDump.getPrincipalName();
if (aceBeansFromConfig.containsPath(jcrPath)) {
LOG.trace("Path {} is explicitly listed in config and hence that ACL is handled later, "
+ "not preceding cleanup needed here", jcrPath);
continue;
}
if (!authorizablesInConfig.contains(principalName)) {
LOG.debug("Principal {} is not contained in config, hence not cleaning its ACE from non-config-contained "
+ "path {}", principalName, jcrPath);
continue;
}
relevantPathsForCleanup.add(jcrPath);
}
}
return relevantPathsForCleanup;
}
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<String> getPrincipalNamesToRemoveAcesFor(AuthorizablesConfig authorizablesBeansfromConfig) {
Set<String> principalsToRemoveAcesFor = authorizablesBeansfromConfig.getPrincipalNames();
Set<String> principalsToBeMigrated = collectPrincipalsToBeMigrated(authorizablesBeansfromConfig);
Collection<?> invalidPrincipalsInConfig = CollectionUtils.intersection(principalsToRemoveAcesFor, principalsToBeMigrated);
if (!invalidPrincipalsInConfig.isEmpty()) {
throw new IllegalArgumentException(
"If migrateFrom feature is used, groups that shall be migrated from must not be present in regular configuration (offending groups: "
+ invalidPrincipalsInConfig + ")");
}
principalsToRemoveAcesFor.addAll(principalsToBeMigrated);
return principalsToRemoveAcesFor;
}
Set<String> collectPrincipalsToBeMigrated(AuthorizablesConfig authorizablesBeansfromConfig) {
Set<String> principalsToBeMigrated = new LinkedHashSet<String>();
for (AuthorizableConfigBean authorizableConfigBean : authorizablesBeansfromConfig) {
String migrateFrom = authorizableConfigBean.getMigrateFrom();
if (StringUtils.isNotBlank(migrateFrom)) {
if (StringUtils.equals(authorizableConfigBean.getPrincipalName(), authorizableConfigBean.getAuthorizableId())) {
// standard case principalName=authorizableId, we can use the migrateFrom property directly
principalsToBeMigrated.add(migrateFrom);
} else {
// external id case: try to derive the correct principal name
String newPrincipalName = authorizableConfigBean.getPrincipalName();
String oldPrincipalName = newPrincipalName.replace(authorizableConfigBean.getAuthorizableId(), migrateFrom);
if (StringUtils.equals(newPrincipalName, oldPrincipalName)) {
throw new IllegalStateException("Could not derive old principal name from newPrincipalName=" + newPrincipalName
+ " and authorizableId=" + authorizableConfigBean.getAuthorizableId() + " (oldPrincipalName="
+ oldPrincipalName + " is equal to new principal name)");
}
principalsToBeMigrated.add(oldPrincipalName);
}
}
}
return principalsToBeMigrated;
}
private void installAces(AcInstallationLog installLog,
AcConfiguration acConfiguration, Map<String, Set<AceBean>> repositoryDumpAceMap, String[] restrictedToPaths, Session session)
throws Exception {
AcesConfig aceBeansFromConfig = acConfiguration.getAceConfig();
// --- installation of ACEs from configuration ---
Map<String, Set<AceBean>> pathBasedAceMapFromConfig = AcHelper
.getPathBasedAceMap(aceBeansFromConfig, AcHelper.ACE_ORDER_ACTOOL_BEST_PRACTICE);
Set<String> principalsToRemoveAcesFor = getPrincipalNamesToRemoveAcesFor(acConfiguration.getAuthorizablesConfig());
removeAcesForPathsNotInConfig(installLog, session, principalsToRemoveAcesFor, repositoryDumpAceMap, aceBeansFromConfig);
Map<String, Set<AceBean>> filteredPathBasedAceMapFromConfig = filterForRestrictedPaths(pathBasedAceMapFromConfig,
restrictedToPaths, installLog);
AceBeanInstaller aceBeanInstaller = acConfiguration.getGlobalConfiguration().getInstallAclsIncrementally()
? aceBeanInstallerIncremental : aceBeanInstallerClassic;
installLog.addMessage(LOG, "*** Starting installation of " + collectAceCount(filteredPathBasedAceMapFromConfig) + " ACE configurations for "
+ filteredPathBasedAceMapFromConfig.size()
+ " paths in content nodes using strategy " + aceBeanInstaller.getClass().getSimpleName() + "...");
aceBeanInstaller.installPathBasedACEs(filteredPathBasedAceMapFromConfig, session, installLog, principalsToRemoveAcesFor,
intermediateSaves);
// if everything went fine (no exceptions), save the session
// thus persisting the changed ACLs
if (session.hasPendingChanges()) {
session.save();
installLog.addMessage(LOG, "Persisted changes of ACLs");
} else {
installLog.addMessage(LOG, "No changes were made to ACLs (session has no pending changes)");
}
}
private Map<String, Set<AceBean>> filterForRestrictedPaths(Map<String, Set<AceBean>> pathBasedAceMapFromConfig,
String[] restrictedToPaths, AcInstallationLog installLog) {
if (restrictedToPaths == null || restrictedToPaths.length == 0) {
return pathBasedAceMapFromConfig;
}
Map<String, Set<AceBean>> filteredPathBasedAceMapFromConfig = new HashMap<String, Set<AceBean>>();
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();
installLog.addMessage(LOG, "Will install AC Config at " + filteredPathBasedAceMapFromConfig.keySet().size()
+ " paths (skipping " + skipped + " due to paths restriction " + Arrays.toString(restrictedToPaths) + ")");
return filteredPathBasedAceMapFromConfig;
}
private int collectAceCount(Map<String, Set<AceBean>> aceMapFromConfig) {
int count = 0;
for (Set<AceBean> acesForGroup : aceMapFromConfig.values()) {
count += acesForGroup.size();
}
return count;
}
private void installAuthorizables(AcInstallationLog installLog, AuthorizablesConfig authorizablesMapfromConfig, Session session)
throws RepositoryException, Exception {
// --- installation of Authorizables from configuration ---
StopWatch stopWatch = new StopWatch();
stopWatch.start();
installLog.addMessage(LOG, "*** Starting installation of " + authorizablesMapfromConfig.size() + " authorizables...");
try {
// only save session if no exceptions occurred
authorizableCreatorService.createNewAuthorizables(authorizablesMapfromConfig, session, installLog);
if (intermediateSaves) {
if (session.hasPendingChanges()) {
session.save();
installLog.addVerboseMessage(LOG, "Saved session after installing authorizables.");
} else {
installLog.addVerboseMessage(LOG,
"After installing authorizables, intermediateSaves is turned on but there are no pending changes.");
}
}
} catch (Exception e) {
throw new AuthorizableCreatorException(e);
}
installLog.addMessage(LOG, "Finished installation of authorizables without errors in "
+ msHumanReadable(stopWatch.getTime()));
}
private void removeObsoleteAuthorizables(AcInstallationLog installLog, Set<String> obsoleteAuthorizables, Session session) {
try {
if (obsoleteAuthorizables.isEmpty()) {
installLog.addVerboseMessage(LOG, "No obsolete authorizables configured");
return;
}
UserManager userManager = AccessControlUtils.getUserManagerAutoSaveDisabled(session);
Set<String> obsoleteAuthorizablesAlreadyPurged = new HashSet<String>();
Iterator<String> obsoleteAuthorizablesIt = obsoleteAuthorizables.iterator();
while (obsoleteAuthorizablesIt.hasNext()) {
String obsoleteAuthorizableId = obsoleteAuthorizablesIt.next();
Authorizable obsoleteAuthorizable = userManager.getAuthorizable(obsoleteAuthorizableId);
if (obsoleteAuthorizable == null) {
obsoleteAuthorizablesAlreadyPurged.add(obsoleteAuthorizableId);
obsoleteAuthorizablesIt.remove();
}
}
if (obsoleteAuthorizables.isEmpty()) {
installLog.addMessage(LOG, "All configured " + obsoleteAuthorizablesAlreadyPurged.size()
+ " obsolete authorizables have already been purged.");
return;
}
installLog.addMessage(LOG, "*** Purging " + obsoleteAuthorizables.size() + " obsolete authorizables... ");
if (!obsoleteAuthorizablesAlreadyPurged.isEmpty()) {
installLog.addMessage(LOG, "(" + obsoleteAuthorizablesAlreadyPurged.size() + " have been purged already)");
}
String purgeAuthorizablesResultMsg = purgeAuthorizables(obsoleteAuthorizables, session);
installLog.addVerboseMessage(LOG, purgeAuthorizablesResultMsg); // this message is too long for regular log
installLog.addMessage(LOG, "Successfully purged " + obsoleteAuthorizables);
} catch (Exception e) {
installLog.addError(LOG, "Could not purge obsolete authorizables " + obsoleteAuthorizables, e);
}
}
private void installMergedConfigurations(
AcInstallationLog installLog,
AcConfiguration acConfiguration, String[] restrictedToPaths, Session session) throws ValueFormatException,
RepositoryException, Exception {
installLog.addVerboseMessage(LOG, "Starting installation of merged configurations...");
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Map<String, Set<AceBean>> repositoryDumpAceMap = null;
LOG.debug("Building dump from repository (to compare delta with config to be installed)");
repositoryDumpAceMap = dumpservice.createAclDumpMap(AcHelper.PATH_BASED_ORDER,
AcHelper.ACE_ORDER_NONE,
new String[0], true, session).getAceDump();
installLog.addMessage(LOG, "Retrieved existing ACLs from repository in " + msHumanReadable(stopWatch.getTime()));
installAcConfiguration(acConfiguration, installLog, repositoryDumpAceMap, restrictedToPaths, session);
}
@Override
public boolean isReadyToStart() {
Session session = null;
String rootPath = getConfiguredAcConfigurationRootPath();
try {
session = repository.loginService(Constants.USER_AC_SERVICE, null);
boolean isReadyToStart = !configFilesRetriever.getConfigFileContentFromNode(rootPath, session).isEmpty();
return isReadyToStart;
} catch (Exception e) {
LOG.warn("Could not retrieve config file content for root path " + configuredAcConfigurationRootPath);
return false;
} finally {
if (session != null) {
session.logout();
}
}
}
@Override
public String purgeACL(String path) {
Session session = null;
String message = "";
boolean flag = true;
try {
session = repository.loginService(Constants.USER_AC_SERVICE, null);
PurgeHelper.purgeAcl(session, path);
session.save();
} catch (Exception e) {
flag = false;
message = e.toString();
LOG.error("Exception: ", e);
} finally {
if (session != null) {
session.logout();
}
}
if (flag) {
message = "Deleted AccessControlList of node: " + path;
AcInstallationLog installLog = new AcInstallationLog();
installLog.addMessage(LOG, "purge method: purgeACL()");
installLog.addMessage(LOG, message);
acHistoryService.persistAcePurgeHistory(installLog);
return message;
}
return "Deletion of ACL failed! Reason:" + message;
}
@Override
public String purgeACLs(String path) {
Session session = null;
String message = "";
boolean flag = true;
try {
session = repository.loginService(Constants.USER_AC_SERVICE, null);
message = PurgeHelper.purgeACLs(session, path);
AcInstallationLog installLog = new AcInstallationLog();
installLog.addMessage(LOG, "purge method: purgeACLs()");
installLog.addMessage(LOG, message);
acHistoryService.persistAcePurgeHistory(installLog);
session.save();
} catch (Exception e) {
LOG.error("Exception: ", e);
flag = false;
message = e.toString();
} finally {
if (session != null) {
session.logout();
}
}
if (flag) {
return message;
}
return "Deletion of ACL failed! Reason:" + message;
}
@Override
public String purgeAuthorizablesFromConfig() {
Session session = null;
String message = "";
try {
session = repository.loginService(Constants.USER_AC_SERVICE, null);
Set<String> authorizabesFromConfigurations = getAllAuthorizablesFromConfig(session);
message = purgeAuthorizables(authorizabesFromConfigurations, session);
AcInstallationLog installLog = new AcInstallationLog();
installLog.addMessage(LOG, "purge method: purgAuthorizablesFromConfig()");
installLog.addMessage(LOG, message);
acHistoryService.persistAcePurgeHistory(installLog);
} catch (Exception e) {
message = "Exception while purging all authorizable from config: " + e;
LOG.error(message, e);
} finally {
if (session != null) {
session.logout();
}
}
return message;
}
@Override
public String purgeAuthorizables(String[] authorizableIds) {
Session session = null;
String message = "";
try {
session = repository.loginService(Constants.USER_AC_SERVICE, null);
Set<String> authorizablesSet = new HashSet<String>(Arrays.asList(authorizableIds));
message = purgeAuthorizables(authorizablesSet, session);
AcInstallationLog installLog = new AcInstallationLog();
installLog.addMessage(LOG, "purge method: purgeAuthorizables()");
installLog.addMessage(LOG, message);
acHistoryService.persistAcePurgeHistory(installLog);
} catch (RepositoryException e) {
LOG.error("Exception: ", e);
message = e.toString();
} finally {
if (session != null) {
session.logout();
}
}
return message;
}
private String purgeAuthorizables(Set<String> authorizableIds, final Session session) {
StopWatch sw = new StopWatch();
sw.start();
StringBuilder message = new StringBuilder();
try {
// first the ACE entries have to be deleted
Set<String> principalIds = new HashSet<String>();
Set<AclBean> aclBeans = QueryHelper.getAuthorizablesAcls(session, authorizableIds, principalIds);
String deleteAcesResultMsg = PurgeHelper.deleteAcesForPrincipalIds(session, principalIds, aclBeans);
message.append(deleteAcesResultMsg);
// then the authorizables can be deleted
UserManager userManager = AccessControlUtils.getUserManagerAutoSaveDisabled(session);
for (String authorizableId : authorizableIds) {
String deleteResultMsg = deleteAuthorizable(authorizableId, userManager);
message.append(deleteResultMsg);
}
session.save();
sw.stop();
String executionTime = AcInstallationLog.msHumanReadable(sw.getTime());
message.append("Purged " + authorizableIds.size() + " authorizables in " + executionTime + "\n");
} catch (Exception e) {
message.append("Deletion of ACEs failed! reason: RepositoryException: " + e + "\n");
LOG.error("Exception while purgin authorizables: " + e, e);
}
return message.toString();
}
private String deleteAuthorizable(final String authorizableId, final UserManager userManager) {
String message;
try {
Authorizable authorizable = userManager.getAuthorizable(authorizableId);
if (authorizable != null) {
authorizable.remove();
message = "Deleted authorizable " + authorizableId + "\n";
} else {
message = "Could not delete authorizable '" + authorizableId + "' because it does not exist\n";
}
} catch (RepositoryException e) {
message = "Error while deleting authorizable '" + authorizableId + "': e=" + e;
LOG.warn("Error while deleting authorizable '" + authorizableId + "': e=" + e, e);
}
return message;
}
@Override
public String getConfiguredAcConfigurationRootPath() {
return configuredAcConfigurationRootPath;
}
@Override
public Set<String> getCurrentConfigurationPaths() {
Session session = null;
Set<String> paths = new LinkedHashSet<String>();
try {
session = repository.loginService(Constants.USER_AC_SERVICE, null);
paths = configFilesRetriever.getConfigFileContentFromNode(configuredAcConfigurationRootPath, session).keySet();
} catch (Exception e) {
LOG.warn("Could not retrieve config file content for root path " + configuredAcConfigurationRootPath + ": e=" + e, e);
} finally {
if (session != null) {
session.logout();
}
}
return paths;
}
public Set<String> getAllAuthorizablesFromConfig(Session session)
throws Exception {
AcInstallationLog history = new AcInstallationLog();
Map<String, String> newestConfigurations = configFilesRetriever.getConfigFileContentFromNode(configuredAcConfigurationRootPath,
session);
AcConfiguration acConfiguration = configurationMerger.getMergedConfigurations(newestConfigurations, history, configReader, session);
Set<String> allAuthorizablesFromConfig = acConfiguration.getAuthorizablesConfig().getAuthorizableIds();
return allAuthorizablesFromConfig;
}
public String getVersion() {
String bundleVersion = FrameworkUtil.getBundle(AcInstallationServiceImpl.class).getVersion().toString();
return bundleVersion;
}
/* --- deprecated methods --- */
@Override
public AcInstallationHistoryPojo execute() {
return execute();
}
@Override
public AcInstallationHistoryPojo execute(String configurationRootPath) {
return execute(configurationRootPath);
}
@Override
public AcInstallationHistoryPojo execute(String[] restrictedToPaths) {
return execute(restrictedToPaths);
}
@Override
public AcInstallationHistoryPojo execute(String configurationRootPath, String[] restrictedToPaths) {
return apply(configurationRootPath, restrictedToPaths);
}
}