Skip to content

Commit ccba27d

Browse files
authored
Merge pull request #540 from Netcentric/bugfix/535-ensure_the_JMX_purge_authorizable_actions_never_purge_system_groups/users
#535 Ensure the JMX purge authorizable actions never purge system groups/users
2 parents 92db477 + 7b1a7bc commit ccba27d

File tree

7 files changed

+188
-251
lines changed

7 files changed

+188
-251
lines changed

accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/authorizableinstaller/impl/AuthorizableInstallerServiceImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
*/
99
package biz.netcentric.cq.tools.actool.authorizableinstaller.impl;
1010

11+
import static biz.netcentric.cq.tools.actool.helper.Constants.PRINCIPAL_EVERYONE;
12+
1113
import java.io.IOException;
1214
import java.security.GeneralSecurityException;
1315
import java.security.cert.Certificate;
@@ -78,8 +80,6 @@ public class AuthorizableInstallerServiceImpl implements
7880

7981
private static final String PATH_SEGMENT_SYSTEMUSERS = "system";
8082

81-
private static final String PRINCIPAL_EVERYONE = "everyone";
82-
8383
// not using org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncContext.REP_EXTERNAL_ID since it is an
8484
// optional dependency and not available in AEM 6.1
8585
public static final String REP_EXTERNAL_ID = "rep:externalId";

accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/Constants.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ private Constants() {
3333
OBSOLETE_AUTHORIZABLES_KEY));
3434

3535
public static final String USER_ANONYMOUS = "anonymous";
36-
36+
public static final String PRINCIPAL_EVERYONE = "everyone";
37+
3738
public static final String GROUPS_ROOT = "/home/groups";
3839
public static final String USERS_ROOT = "/home/users";
3940

accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/PurgeHelper.java

Lines changed: 10 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -8,67 +8,44 @@
88
*/
99
package biz.netcentric.cq.tools.actool.helper;
1010

11-
import static biz.netcentric.cq.tools.actool.history.PersistableInstallationLogger.msHumanReadable;
12-
13-
import java.util.Iterator;
14-
import java.util.Set;
15-
16-
import javax.jcr.AccessDeniedException;
1711
import javax.jcr.Node;
1812
import javax.jcr.NodeIterator;
19-
import javax.jcr.PathNotFoundException;
2013
import javax.jcr.RepositoryException;
2114
import javax.jcr.Session;
22-
import javax.jcr.UnsupportedRepositoryOperationException;
23-
import javax.jcr.lock.LockException;
2415
import javax.jcr.query.Query;
2516
import javax.jcr.query.QueryResult;
26-
import javax.jcr.security.AccessControlEntry;
27-
import javax.jcr.security.AccessControlException;
2817
import javax.jcr.security.AccessControlManager;
2918
import javax.jcr.security.AccessControlPolicy;
30-
import javax.jcr.version.VersionException;
3119

3220
import org.apache.commons.lang3.StringUtils;
33-
import org.apache.commons.lang3.time.StopWatch;
34-
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
35-
import org.apache.sling.api.resource.Resource;
36-
import org.apache.sling.api.resource.ResourceResolver;
3721
import org.slf4j.Logger;
3822
import org.slf4j.LoggerFactory;
3923

4024
public class PurgeHelper {
4125
public static final Logger LOG = LoggerFactory.getLogger(PurgeHelper.class);
4226

43-
44-
public static String purgeACLs(final Session session, final String path)
45-
throws Exception {
27+
public static String purgeACLs(final Session session, final String path) throws RepositoryException {
4628

4729
StringBuilder message = new StringBuilder();
4830
if (StringUtils.isNotBlank(path)) {
4931
String queryString = "/jcr:root" + path.trim() + "//rep:policy";
50-
Query query = session.getWorkspace().getQueryManager()
51-
.createQuery(queryString, Query.XPATH);
32+
Query query = session.getWorkspace().getQueryManager().createQuery(queryString, Query.XPATH);
5233
QueryResult result = query.execute();
5334
NodeIterator nodeIterator = result.getNodes();
5435

55-
AccessControlManager accessManager = session
56-
.getAccessControlManager();
36+
AccessControlManager accessManager = session.getAccessControlManager();
5737

5838
while (nodeIterator.hasNext()) {
5939
Node res = nodeIterator.nextNode().getParent();
6040
if (res != null) {
61-
AccessControlPolicy[] policies = accessManager
62-
.getPolicies(res.getPath());
41+
AccessControlPolicy[] policies = accessManager.getPolicies(res.getPath());
6342
for (int j = 0; j < policies.length; j++) {
6443
accessManager.removePolicy(res.getPath(), policies[j]);
6544
}
66-
message.append("Removed all policies from node "
67-
+ res.getPath() + ".\n");
45+
message.append("Removed all policies from node " + res.getPath() + ".\n");
6846
}
6947
}
70-
message.append("\n\nCompleted removing ACLs from path: " + path
71-
+ " and it's subpaths!");
48+
message.append("\n\nCompleted removing ACLs from path: " + path + " and it's subpaths!");
7249
}
7350

7451
session.save();
@@ -77,98 +54,18 @@ public static String purgeACLs(final Session session, final String path)
7754
}
7855

7956
public static void purgeAcl(final Session session, final String path)
80-
throws Exception {
57+
throws RepositoryException {
8158

8259
if (StringUtils.isNotBlank(path)) {
83-
AccessControlManager accessManager = session
84-
.getAccessControlManager();
60+
AccessControlManager accessManager = session.getAccessControlManager();
8561
Node node = session.getNode(path);
8662

87-
AccessControlPolicy[] policies = accessManager.getPolicies(node
88-
.getPath());
63+
AccessControlPolicy[] policies = accessManager.getPolicies(node.getPath());
8964
for (int i = 0; i < policies.length; i++) {
9065
accessManager.removePolicy(node.getPath(), policies[i]);
91-
AcHelper.LOG.info("Removed all policies from node "
92-
+ node.getPath() + ".\n");
66+
LOG.info("Removed all policies from node {}", node.getPath());
9367
}
9468
}
9569
}
9670

97-
public static void purgeACLs(final ResourceResolver resourceResolver,
98-
final String[] paths) throws Exception {
99-
Session session = resourceResolver.adaptTo(Session.class);
100-
101-
for (int i = 0; i < paths.length; i++) {
102-
if (StringUtils.isNotBlank(paths[i])) {
103-
String query = "/jcr:root" + paths[i].trim() + "//rep:policy";
104-
Iterator<Resource> results = resourceResolver.findResources(
105-
query, Query.XPATH);
106-
AccessControlManager accessManager = session
107-
.getAccessControlManager();
108-
109-
while (results.hasNext()) {
110-
Resource res = results.next().getParent();
111-
if (res != null) {
112-
AccessControlPolicy[] policies = accessManager
113-
.getPolicies(res.getPath());
114-
for (int j = 0; j < policies.length; j++) {
115-
accessManager.removePolicy(res.getPath(),
116-
policies[j]);
117-
}
118-
}
119-
}
120-
}
121-
}
122-
session.save();
123-
}
124-
125-
public static String deleteAcesForPrincipalIds(final Session session,
126-
final Set<String> principalIds, final Set<AclBean> aclBeans)
127-
throws UnsupportedRepositoryOperationException,
128-
RepositoryException, AccessControlException, PathNotFoundException,
129-
AccessDeniedException, LockException, VersionException {
130-
131-
StopWatch sw = new StopWatch();
132-
sw.start();
133-
StringBuilder message = new StringBuilder();
134-
AccessControlManager aMgr = session.getAccessControlManager();
135-
long aceCounter = 0;
136-
137-
for (AclBean aclBean : aclBeans) {
138-
if (aclBean == null) {
139-
continue;
140-
}
141-
142-
JackrabbitAccessControlList acl = aclBean.getAcl();
143-
for (AccessControlEntry ace : acl.getAccessControlEntries()) {
144-
String principalId = ace.getPrincipal().getName();
145-
if (principalIds.contains(principalId)) {
146-
String parentNodePath = aclBean.getParentPath();
147-
acl.removeAccessControlEntry(ace);
148-
boolean aclEmpty = acl.isEmpty();
149-
if (!aclEmpty) {
150-
aMgr.setPolicy(aclBean.getParentPath(), acl);
151-
} else {
152-
aMgr.removePolicy(aclBean.getParentPath(), acl);
153-
}
154-
155-
String msg = "Path " + parentNodePath + ": Removed entry for '" + principalId + "' from ACL "
156-
+ (aclEmpty ? " (and the now emtpy ACL itself)" : "");
157-
LOG.info(msg);
158-
message.append(msg + "\n");
159-
aceCounter++;
160-
}
161-
}
162-
163-
}
164-
sw.stop();
165-
String executionTime = msHumanReadable(sw.getTime());
166-
String resultMsg = (aceCounter > 0)
167-
? "Deleted " + aceCounter + " ACEs for " + principalIds.size() + " principals in " + executionTime
168-
: "Did not delete any ACEs";
169-
message.append(resultMsg + "\n");
170-
LOG.debug(resultMsg);
171-
172-
return message.toString();
173-
}
17471
}

accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/history/AcHistoryService.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ public interface AcHistoryService {
1616

1717
public void persistAcePurgeHistory(PersistableInstallationLogger history);
1818

19-
/**
20-
* Returns history items of previous runs
21-
* @return Set of AcToolExecutions
22-
*/
19+
/** Returns history items of previous runs
20+
*
21+
* @return Set of AcToolExecutions */
2322
public List<AcToolExecution> getAcToolExecutions();
2423

2524
public String getLastInstallationHistory();
@@ -28,10 +27,8 @@ public interface AcHistoryService {
2827

2928
public boolean wasLastPersistHistoryCallSuccessful();
3029

31-
/**
32-
* @deprecated Use {@link #getAcToolExecutions()} instead
33-
* @return
34-
*/
30+
/** @deprecated Use {@link #getAcToolExecutions()} instead
31+
* @return */
3532
public String[] getInstallationLogPaths();
36-
33+
3734
}

accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/history/impl/AcHistoryServiceImpl.java

Lines changed: 26 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
import java.util.Iterator;
1515
import java.util.List;
1616
import java.util.Map;
17-
import java.util.Set;
18-
import java.util.TreeSet;
1917

2018
import javax.jcr.Node;
2119
import javax.jcr.NodeIterator;
@@ -37,8 +35,6 @@
3735

3836
import com.day.cq.commons.jcr.JcrConstants;
3937

40-
import biz.netcentric.cq.tools.actool.comparators.TimestampPropertyComparator;
41-
import biz.netcentric.cq.tools.actool.helper.Constants;
4238
import biz.netcentric.cq.tools.actool.history.AcHistoryService;
4339
import biz.netcentric.cq.tools.actool.history.AcToolExecution;
4440
import biz.netcentric.cq.tools.actool.history.PersistableInstallationLogger;
@@ -172,7 +168,7 @@ public String getLastInstallationHistory() {
172168
history = "no history found!";
173169
}
174170
} catch (RepositoryException e) {
175-
LOG.error("RepositoryException: ", e);
171+
LOG.error("RepositoryException: {}", e, e);
176172
} finally {
177173
if (session != null) {
178174
session.logout();
@@ -235,64 +231,46 @@ public String getLogFromHistory(int n, boolean inHtmlFormat, boolean includeVerb
235231

236232
@Override
237233
public void persistAcePurgeHistory(PersistableInstallationLogger installLog) {
238-
Session session = null;
239234

235+
Session session = null;
240236
try {
241237
session = repository.loginService(null, null);
238+
242239
Node acHistoryRootNode = HistoryUtils.getAcHistoryRootNode(session);
243-
NodeIterator nodeIterator = acHistoryRootNode.getNodes();
244-
Set<Node> historyNodes = new TreeSet<Node>(
245-
new TimestampPropertyComparator());
246-
Node newestHistoryNode = null;
247-
while (nodeIterator.hasNext()) {
248-
historyNodes.add(nodeIterator.nextNode());
240+
241+
Node purgeHistoryNode = acHistoryRootNode.addNode("purge_" + System.currentTimeMillis(), HistoryUtils.NODETYPE_NT_UNSTRUCTURED);
242+
243+
// if there is already a purge history node, order the new one before so
244+
// the newest one is always on top
245+
NodeIterator nodeIt = acHistoryRootNode.getNodes();
246+
Node previousPurgeNode = null;
247+
while (nodeIt.hasNext()) {
248+
Node currNode = nodeIt.nextNode();
249+
// get previous purgeHistory node
250+
if (currNode.getName().contains("purge_")) {
251+
previousPurgeNode = currNode;
252+
break;
253+
}
249254
}
250-
if (!historyNodes.isEmpty()) {
251-
newestHistoryNode = historyNodes.iterator().next();
252-
persistPurgeAceHistory(session, installLog, newestHistoryNode);
253-
session.save();
255+
256+
if (previousPurgeNode != null) {
257+
acHistoryRootNode.orderBefore(purgeHistoryNode.getName(), previousPurgeNode.getName());
254258
}
255259

260+
installLog.addMessage(LOG, "Saved history in node: " + purgeHistoryNode.getPath());
261+
HistoryUtils.setHistoryNodeProperties(purgeHistoryNode, installLog, "purge");
262+
HistoryUtils.saveLogs(purgeHistoryNode, installLog);
263+
264+
session.save();
256265
} catch (RepositoryException e) {
257-
LOG.error("Exception: ", e);
266+
LOG.error("RepositoryException: ", e);
258267
} finally {
259268
if (session != null) {
260269
session.logout();
261270
}
262271
}
263272
}
264273

265-
private static Node persistPurgeAceHistory(final Session session,
266-
PersistableInstallationLogger installLog, final Node historyNode)
267-
throws RepositoryException {
268-
269-
Node purgeHistoryNode = historyNode.addNode(
270-
"purge_" + System.currentTimeMillis(),
271-
HistoryUtils.NODETYPE_NT_UNSTRUCTURED);
272-
273-
// if there is already a purge history node, order the new one before so
274-
// the newest one is always on top
275-
NodeIterator nodeIt = historyNode.getNodes();
276-
Node previousPurgeNode = null;
277-
while (nodeIt.hasNext()) {
278-
Node currNode = nodeIt.nextNode();
279-
// get previous purgeHistory node
280-
if (currNode.getName().contains("purge_")) {
281-
previousPurgeNode = currNode;
282-
break;
283-
}
284-
}
285-
286-
if (previousPurgeNode != null) {
287-
historyNode.orderBefore(purgeHistoryNode.getName(),
288-
previousPurgeNode.getName());
289-
}
290-
291-
installLog.addMessage(LOG, "Saved history in node: " + purgeHistoryNode.getPath());
292-
HistoryUtils.setHistoryNodeProperties(purgeHistoryNode, installLog, "purge");
293-
return historyNode;
294-
}
295-
296274
@Override
297275
public boolean wasLastPersistHistoryCallSuccessful() {
298276
return wasLastPersistHistoryCallSuccessful;

accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/history/impl/HistoryUtils.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,8 @@ public static Node persistHistory(final Session session,
133133
Node newHistoryNode = safeGetNode(acHistoryRootNode, name, NODETYPE_NT_UNSTRUCTURED);
134134
String path = newHistoryNode.getPath();
135135
setHistoryNodeProperties(newHistoryNode, installLog, trigger);
136-
137-
// not ideal to save both variants, but the easiest for now
138-
JcrUtils.putFile(newHistoryNode, LOG_FILE_NAME_VERBOSE, "text/plain",
139-
new ByteArrayInputStream(installLog.getVerboseMessageHistory().getBytes()));
140-
JcrUtils.putFile(newHistoryNode, LOG_FILE_NAME, "text/plain",
141-
new ByteArrayInputStream(installLog.getMessageHistory().getBytes()));
142-
136+
saveLogs(newHistoryNode, installLog);
137+
143138
deleteObsoleteHistoryNodes(acHistoryRootNode, nrOfHistoriesToSave);
144139

145140
Node previousHistoryNode = (Node) acHistoryRootNode.getNodes().next();
@@ -153,6 +148,14 @@ public static Node persistHistory(final Session session,
153148
return newHistoryNode;
154149
}
155150

151+
static void saveLogs(Node historyNode, PersistableInstallationLogger installLog) throws RepositoryException {
152+
// not ideal to save both variants, but the easiest for now
153+
JcrUtils.putFile(historyNode, LOG_FILE_NAME_VERBOSE, "text/plain",
154+
new ByteArrayInputStream(installLog.getVerboseMessageHistory().getBytes()));
155+
JcrUtils.putFile(historyNode, LOG_FILE_NAME, "text/plain",
156+
new ByteArrayInputStream(installLog.getMessageHistory().getBytes()));
157+
}
158+
156159
private static boolean isInStrackTracke(StackTraceElement[] stackTrace, Class<?> classToSearch) {
157160
return isInStrackTracke(stackTrace, classToSearch.getName());
158161
}

0 commit comments

Comments
 (0)