We have a requirement to fetch the effective ACL permissions on all the pages or assets of an AEM website for all the users. The goal is to determine the list of users who have read permissions or write permissions. The users are generally synced via IDP integration to Adobe Admin Console IMS. There could be close to a million users.
Below are some of the options / endpoints we have already explored, which did not meet the requirement:
- http://localhost:4502/bin/security/authorizables.json?path=/content/dam/we-retail/en/features/tracki... - returns the list of authorizables and their details such as groups the user is part of, or members part of that group, their home directory, principal name etc. But does not return effective ACLs
- http://localhost:4502/bin/policies?principal=test-user Return the Access Control Policies that are applicable for the user but not effective ACLs path wise.
- http://localhost:4502/content/wknd/us/.permissions.json?privileges=jcr:read - confirms if the current user has been granted the said privilege.
- http://localhost:4502/.cqactions.json?path=/content/wknd&_charset_=utf-8&depth=100&authorizableId=te... - This endpoint returns the declared privileges for the given authorizable ID on the specific path and all of its children recursively until the depth specified. This is the closest endpoint that meets the requirement to an extent, however, it would also mean that we will have to hit this request iterating through all the users on AEM. If there were a million users, we will need to hit this endpoint a million times.
- Programmatically fetching ACLs using JackrabbitAccessControlList, AccessControlManager API - sample code snippet below:
javax.jcr.security.AccessControlEntry;
javax.jcr.security.AccessControlList;
javax.jcr.security.AccessControlManager;
javax.jcr.security.AccessControlPolicy;
javax.jcr.security.Privilege;
AccessControlManager accessControlManager = session.getAccessControlManager();
AccessControlPolicy[] policies = accessControlManager.getEffectivePolicies(absPath);
List<HashMap<String, Object>> eAclList = new ArrayList<>();
for (AccessControlPolicy accessControlPolicy : policies) {
if (accessControlPolicy instanceof AccessControlList) {
HashMap<String, Object> eAcl = new HashMap<>();
AccessControlList acl = (AccessControlList) accessControlPolicy;
AccessControlEntry[] entries = acl.getAccessControlEntries();
for (AccessControlEntry entry : entries) {
logger.info("Principal: {}", entry.getPrincipal().getName());
eAcl.put("Principal", entry.getPrincipal().getName());
ArrayList<String> privileges = new ArrayList<>();
logger.info("Privileges: ");
for (Privilege privilege : entry.getPrivileges()) {
logger.info("\t {}", privilege.getName());
privileges.add(privilege.getName());
}
eAcl.put("Privileges", privileges);
}
eAclList.add(eAcl);
} else {
logger.error("Encountered an unsupported type of AccessControlPolicy.");
}
logger.info("EACL on {} = {}", absPath, eAclList);
}
Gson mapper = new Gson();
String jsonResponse = mapper.toJson(eAclList);
Sample JSON Response:
[
{
"Privileges": [
"jcr:read",
"rep:write"
],
"Principal": "statistics-service"
},
{
"Privileges": [
"jcr:nodeTypeManagement",
"jcr:read",
"jcr:removeChildNodes",
"jcr:addChildNodes"
],
"Principal": "taskmanagement-service"
},
{
"Privileges": [
"jcr:write"
],
"Principal": "test-user"
}
]
The Privileges API only provides the list of privileges for all the principals but not the permission granted for those privileges for the user. To determine the permission granted, we would require a session to be created for that user and check if the user has permission on the given path. This would not be an efficient approach as we would be creating million sessions if we had a million users, for all the pages in the content repository.
Is there a REST Endpoint that is already available on AEM to fetch a list of users who have been granted read/write permission (not just privileges, but privileges granted - deny /allow) on a particular content root such as /content/wknd or /content/dam/wknd-shared?
If not, how can this be achieve programmatically without having to create a session for each user?