diff --git a/accesscontroltool-bundle/pom.xml b/accesscontroltool-bundle/pom.xml
index 94f51a07..a067cb59 100644
--- a/accesscontroltool-bundle/pom.xml
+++ b/accesscontroltool-bundle/pom.xml
@@ -11,7 +11,7 @@
biz.netcentric.cq.tools.accesscontroltool
accesscontroltool
- 1.6.1
+ 1.6.2
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 b629c194..5883cc57 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
@@ -144,18 +144,7 @@ private static void writeAcBeansToRepository(final Session session,
} else {
history.addVerboseMessage("starting installation of bean: \n"
+ bean);
- // check if path exists in CRX
- if (session.itemExists(bean.getJcrPath())) {
- bean.writeToRepository(session, currentPrincipal, history);
- } else {
- String warningMessage = "path: "
- + bean.getJcrPath()
- + " doesn't exist in repository. Skipped installation of this ACE!";
- LOG.warn(warningMessage);
- history.addWarning(warningMessage);
- continue;
- }
-
+ bean.install(session, currentPrincipal, history);
}
}
}
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 415c94b2..5724221e 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
@@ -22,6 +22,7 @@
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.AccessControlException;
import javax.jcr.security.AccessControlManager;
@@ -44,8 +45,8 @@
/**
* This class provides common access control related utilities.
+ * Mostly a copy of org.apache.jackrabbit.commons.AccessControlUtils.
*/
-
public class AccessControlUtils {
private AccessControlUtils() {
@@ -258,45 +259,6 @@ public static boolean addAccessControlEntry(Session session,
return false;
}
- public static void addActions(Session session, AceBean aceBean,
- Principal principal, AcInstallationHistoryPojo history)
- throws RepositoryException {
-
- boolean isAllow = aceBean.isAllow();
- String[] actions = aceBean.getActions();
- CqActions cqActions = new CqActions(session);
- String absPath = aceBean.getJcrPath();
- String globString = aceBean.getRepGlob();
- String[] privNames = aceBean.getPrivileges();
- Map actionMap = new HashMap();
-
- if (actions != null) {
- for (String action : actions) {
- if ("create".equals(action) || "modify".equals(action) || "delete".equals(action)) {
- actionMap.put(action, isAllow);
- }
- }
-
- Collection inheritedAllows = new HashSet();
- inheritedAllows.add("read");
-
- LOG.info("setting actions for path: {} and principal {}", absPath,
- principal.getName());
- cqActions.installActions(absPath, principal, actionMap,
- inheritedAllows);
- } else {
- String message = "Could not install Actions for " + aceBean
- + ", no actions defined!";
- history.addWarning(message);
-
- }
- // if(privNames != null){
- // installPermissions(session, absPath, principal, isAllow, globString,
- // privNames);
- // }
-
- }
-
private static Principal getEveryonePrincipal(Session session)
throws RepositoryException {
if (session instanceof JackrabbitSession) {
@@ -399,5 +361,17 @@ static JackrabbitAccessControlList getModifiableAcl(
}
return null;
}
-
+
+ public static void extendExistingAceWithRestrictions(JackrabbitAccessControlList accessControlList, JackrabbitAccessControlEntry accessControlEntry, Map restrictions) throws AccessControlException, UnsupportedRepositoryOperationException, RepositoryException {
+ // 1. add new entry
+ if (!accessControlList.addEntry(accessControlEntry.getPrincipal(), accessControlEntry.getPrivileges(), accessControlEntry.isAllow(), restrictions)) {
+ throw new IllegalStateException("Could not add entry, probably because it was already there!");
+ }
+ // we assume the entry being added is the last one
+ AccessControlEntry newAccessControlEntry = accessControlList.getAccessControlEntries()[accessControlList.size() - 1];
+ // 2. put it to the right position now!
+ accessControlList.orderBefore(newAccessControlEntry, accessControlEntry);
+ // 3. remove old entry
+ accessControlList.removeAccessControlEntry(accessControlEntry);
+ }
}
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/AceBean.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/AceBean.java
index 104952ec..459c4d4d 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/AceBean.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/AceBean.java
@@ -10,18 +10,24 @@
import java.security.Principal;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.Privilege;
import org.apache.commons.lang.StringUtils;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
import biz.netcentric.cq.tools.actool.dumpservice.AcDumpElement;
@@ -49,6 +55,9 @@ public class AceBean implements AcDumpElement {
private String permission;
private String[] actions;
private String assertedExceptionString;
+
+
+ public static final String RESTRICTION_NAME_GLOB = "rep:glob";
public String getAssertedExceptionString() {
return assertedExceptionString;
@@ -242,6 +251,7 @@ private static Set removeRedundantPrivileges(Session session, String[] p
return cleanedPrivileges;
}
for (String action : actions) {
+ @SuppressWarnings("deprecation")
Set coveredPrivileges = cqActions.getPrivileges(action);
for (Privilege coveredPrivilege : coveredPrivileges) {
cleanedPrivileges.remove(coveredPrivilege.getName());
@@ -249,47 +259,101 @@ private static Set removeRedundantPrivileges(Session session, String[] p
}
return cleanedPrivileges;
}
+
/**
- * Persists the AccessControlEntry being represented by this bean to the
- * repository
+ * Creates a restriction map being used in {@link JackrabbitAccessControlList#addEntry(Principal, Privilege[], boolean, Map)} out of the set actions on this bean.
+ *
+ * @param session the session
+ * @param acl the access control list for which this restriction map should be used
+ * @return a map with restriction names as keys and restriction values as values.
+ * @throws ValueFormatException
+ * @throws UnsupportedRepositoryOperationException
+ * @throws RepositoryException
*/
- public void writeToRepository(final Session session, Principal principal, AcInstallationHistoryPojo history)
- throws RepositoryException {
- AccessControlManager acMgr = session.getAccessControlManager();
-
- // Convert actions to permissions, if necessary
- if (getActions() != null) {
- // install actions
- history.addVerboseMessage("adding action for path: "
- + getJcrPath() + ", principal: "
- + principal.getName() + ", actions: "
- + getActionsString() + ", permission: "
- + getPermission());
- AccessControlUtils.addActions(session, this, principal,
- history);
- removeRedundantPrivileges(session);
+ private Map getSingleValueRestrictions(Session session, JackrabbitAccessControlList acl) throws ValueFormatException, UnsupportedRepositoryOperationException, RepositoryException {
+ Collection supportedRestrictionNames = Arrays.asList(acl.getRestrictionNames());
+ if (getRepGlob() != null) {
+ if (!supportedRestrictionNames.contains(RESTRICTION_NAME_GLOB)) {
+ throw new IllegalStateException("The AccessControlList at " + acl.getPath() + " does not support setting rep:glob restrictions!");
+ }
+ Value v = session.getValueFactory().createValue(getRepGlob(), acl.getRestrictionType(RESTRICTION_NAME_GLOB));
+ return Collections.singletonMap(RESTRICTION_NAME_GLOB, v);
+ } else {
+ return Collections.emptyMap();
+ }
+ }
+
+ /**
+ * Creates an action map being used in {@link CqActions#installActions(String, Principal, Map, Collection)} out of the set actions on this bean.
+ * @return a map containing actions as keys and booleans representing {@code true} for allow and {@code false} for deny.
+ */
+ private Map getActionMap() {
+ if (actions == null) {
+ return Collections.emptyMap();
+ }
+ Map actionMap = new HashMap();
+ for (String action : actions) {
+ actionMap.put(action, isAllow());
}
-
-
- JackrabbitAccessControlList acl = AccessControlUtils.getModifiableAcl(
- acMgr, getJcrPath());
- Set privileges = AccessControlUtils.getPrivilegeSet(
- getPrivileges(), acMgr);
+ return actionMap;
+ }
+
+ /**
+ * Installs the CQ actions in the repository.
+ *
+ * @param principal
+ * @param acl
+ * @param session
+ * @param acMgr
+ * @return either the same acl as given in the parameter {@code acl} if no actions have been installed otherwise the new AccessControlList (comprising the entres being installed for the actions).
+ * @throws RepositoryException
+ */
+ private JackrabbitAccessControlList installActions(Principal principal, JackrabbitAccessControlList acl, Session session, AccessControlManager acMgr) throws RepositoryException {
+ Map actionMap = getActionMap();
+ if (actionMap.isEmpty()) {
+ return acl;
+ }
+ int previousAclSize = acl.size();
- if (!privileges.isEmpty()) {
- Map restrictions = null;
- if (getRepGlob() != null) {
- // is rep:glob supported?
- for (String rName : acl.getRestrictionNames()) {
- if ("rep:glob".equals(rName)) {
- Value v = session.getValueFactory().createValue(
- getRepGlob(), acl.getRestrictionType(rName));
- restrictions = Collections.singletonMap(rName, v);
- break;
- }
- }
+ CqActions cqActions = new CqActions(session);
+ Collection inheritedAllows = cqActions.getAllowedActions(
+ getJcrPath(), Collections.singleton(principal));
+ // this does always install new entries
+ cqActions.installActions(getJcrPath(), principal, actionMap,
+ inheritedAllows);
+
+ // since the aclist has been modified, retrieve it again
+ JackrabbitAccessControlList newAcl = AccessControlUtils.getAccessControlList(session, getJcrPath());
+ Map restrictions = getSingleValueRestrictions(session, acl);
+ if (restrictions.isEmpty()) {
+ return newAcl;
+ }
+ // additionally set restrictions on the installed actions (this is not supported by CQ Security API)
+ int newAclSize = newAcl.size();
+ if (previousAclSize >= newAclSize) {
+ throw new IllegalStateException("No new entries have been set for AccessControlList at " + getJcrPath());
+ }
+ AccessControlEntry[] aces = newAcl.getAccessControlEntries();
+ for (int acEntryIndex = previousAclSize; acEntryIndex < newAclSize; acEntryIndex++) {
+ if (!(aces[acEntryIndex] instanceof JackrabbitAccessControlEntry)) {
+ throw new IllegalStateException("Can not deal with non JackrabbitAccessControlEntrys, but entry is of type " + aces[acEntryIndex].getClass().getName());
+ }
+ JackrabbitAccessControlEntry ace = (JackrabbitAccessControlEntry)aces[acEntryIndex];
+ // only extend those AccessControlEntries which do not yet have a restriction
+ if (ace.getRestrictions("rep:glob") == null) {
+ // modify this AccessControlEntry by adding the restriction
+ AccessControlUtils.extendExistingAceWithRestrictions(newAcl, ace, restrictions);
}
- if (restrictions != null) {
+ }
+ return newAcl;
+ }
+
+ private boolean installPrivileges(Principal principal, JackrabbitAccessControlList acl, Session session, AccessControlManager acMgr) throws RepositoryException {
+ // then install remaining privileges
+ Set privileges = AccessControlUtils.getPrivilegeSet(getPrivileges(), acMgr);
+ if (!privileges.isEmpty()) {
+ Map restrictions = getSingleValueRestrictions(session, acl);
+ if (!restrictions.isEmpty()) {
acl.addEntry(principal, (Privilege[]) privileges
.toArray(new Privilege[privileges.size()]), isAllow(),
restrictions);
@@ -297,6 +361,41 @@ public void writeToRepository(final Session session, Principal principal, AcInst
acl.addEntry(principal, (Privilege[]) privileges
.toArray(new Privilege[privileges.size()]), isAllow());
}
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Installs the AccessControlEntry being represented by this bean in the
+ * repository
+ */
+ public void install(final Session session, Principal principal,
+ AcInstallationHistoryPojo history) throws RepositoryException {
+ AccessControlManager acMgr = session.getAccessControlManager();
+
+ JackrabbitAccessControlList acl = AccessControlUtils.getModifiableAcl(
+ acMgr, getJcrPath());
+ if (acl == null) {
+ history.addWarning("Skipped installing privileges/actions for non existing path: " + getJcrPath());
+ return;
+ }
+
+ // first install actions
+ JackrabbitAccessControlList newAcl = installActions(principal, acl, session, acMgr);
+ if (acl != newAcl) {
+ history.addVerboseMessage("added action(s) for path: " + getJcrPath()
+ + ", principal: " + principal.getName() + ", actions: "
+ + getActionsString() + ", allow: " + isAllow());
+ removeRedundantPrivileges(session);
+ acl = newAcl;
+ }
+
+ // then install (remaining) privileges
+ if (installPrivileges(principal, acl, session, acMgr)) {
+ history.addVerboseMessage("added privilege(s) for path: " + getJcrPath()
+ + ", principal: " + principal.getName() + ", privileges: "
+ + getPrivilegesString() + ", allow: " + isAllow());
}
acMgr.setPolicy(getJcrPath(), acl);
}
diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installationhistory/HistoryEntry.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installationhistory/HistoryEntry.java
index 1c8b9e0a..bf47982e 100644
--- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installationhistory/HistoryEntry.java
+++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installationhistory/HistoryEntry.java
@@ -47,4 +47,12 @@ public void setIndex(long index) {
this.index = index;
}
+ @Override
+ public String toString() {
+ return "HistoryEntry [timestamp=" + timestamp + ", message=" + message
+ + ", index=" + index + "]";
+ }
+
+
+
}
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 bb7a293f..4c284aa8 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
@@ -4,6 +4,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import biz.netcentric.cq.tools.actool.installationhistory.AcInstallationHistoryPojo;
+import biz.netcentric.cq.tools.actool.installationhistory.HistoryEntry;
+
import com.day.jcr.vault.packaging.InstallContext;
import com.day.jcr.vault.packaging.PackageException;
@@ -45,11 +48,30 @@ public void execute(InstallContext context) throws PackageException {
}
//
try {
- acService.installYamlFilesFromPackage(context.getPackage().getArchive(), context.getSession());
- log("Installed ACLs through AcToolInstallHook!", context.getOptions());
- } catch (Exception e) {
- log("Exception while installing configurations: " + e, context.getOptions());
- throw new PackageException(e.getMessage(), e);
+ AcInstallationHistoryPojo history;
+ try {
+ history = acService.installYamlFilesFromPackage(context
+ .getPackage().getArchive(), context.getSession());
+
+ } catch (Exception e) {
+ log("Exception while installing configurations: " + e,
+ context.getOptions());
+ throw new PackageException(e.getMessage(), e);
+ }
+
+ if (!history.isSuccess()) {
+ for (HistoryEntry entry : history.getException()) {
+ log(entry.toString(), context.getOptions());
+ }
+ throw new PackageException(
+ "Could not install configurations. Check log for detailed error message!");
+ } else {
+ // convert to correct (HTML) linebreaks for the package manager
+ String log = history.toString().replaceAll("\\\n", "
");
+ log(log, context.getOptions());
+ log("Installed ACLs successfully through AcToolInstallHook!",
+ context.getOptions());
+ }
} finally {
getBundleContext().ungetService(acToolInstallHookService);
}
@@ -61,6 +83,4 @@ public void execute(InstallContext context) throws PackageException {
}
}
-
-
}
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 de13afe8..fa7a057d 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
@@ -2,11 +2,13 @@
import javax.jcr.Session;
+import biz.netcentric.cq.tools.actool.installationhistory.AcInstallationHistoryPojo;
+
import com.day.jcr.vault.fs.io.Archive;
public interface AcToolInstallHookService {
- public void installYamlFilesFromPackage(Archive archive, Session session)
+ public AcInstallationHistoryPojo installYamlFilesFromPackage(Archive archive, Session session)
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 1bd7b134..9713f706 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
@@ -32,7 +32,7 @@ public class AcToolInstallHookServiceImpl implements AcToolInstallHookService {
private ConfigFilesRetriever configFilesRetriever;
@Override
- public void installYamlFilesFromPackage(Archive archive, Session session)
+ public AcInstallationHistoryPojo installYamlFilesFromPackage(Archive archive, Session session)
throws Exception {
AcInstallationHistoryPojo history = new AcInstallationHistoryPojo();
Set authorizableInstallationHistorySet = new LinkedHashSet();
@@ -47,5 +47,6 @@ public void installYamlFilesFromPackage(Archive archive, Session session)
// TODO: acHistoryService.persistHistory(history,
// this.configurationPath);
}
+ return history;
}
}
diff --git a/accesscontroltool-oakindex-package/pom.xml b/accesscontroltool-oakindex-package/pom.xml
index 98c10c11..11f462a0 100644
--- a/accesscontroltool-oakindex-package/pom.xml
+++ b/accesscontroltool-oakindex-package/pom.xml
@@ -15,7 +15,7 @@
biz.netcentric.cq.tools.accesscontroltool
accesscontroltool
- 1.6.1
+ 1.6.2
diff --git a/accesscontroltool-package/pom.xml b/accesscontroltool-package/pom.xml
index d34571f0..79ef5221 100644
--- a/accesscontroltool-package/pom.xml
+++ b/accesscontroltool-package/pom.xml
@@ -15,7 +15,7 @@
biz.netcentric.cq.tools.accesscontroltool
accesscontroltool
- 1.6.1
+ 1.6.2
diff --git a/pom.xml b/pom.xml
index 8222070f..773810a7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
biz.netcentric.cq.tools.accesscontroltool
accesscontroltool
- 1.6.1
+ 1.6.2
pom
Access Control Tool - Reactor Project
@@ -339,7 +339,7 @@
external.atlassian.jgitflow
jgitflow-maven-plugin
- 1.0-m4.3
+ 1.0-m5.1
true
true