Expand my Community achievements bar.

User Group Permission

Avatar

Community Advisor

Hey Team,

I have a use case related to ACLs:
I overlaid /libs/cq/core/content/tools to create a custom tool under the Tools section of the AEM console. Now, I want to hide it for all users except one specific user group. How can I achieve this?

I tried using the rep:policy node, where I denied access for the everyone group and allowed it for the group I created, but it's not working.

Can anyone please help me here?

Thanks

4 Replies

Avatar

Level 4

Creating custom tools in the AEM console and restricting access through ACLs can be tricky because of how permission inheritance works in the JCR repository. When you overlay /libs/cq/core/content/tools and add a rep:policy node, you're likely encountering one of these issues:

 

  • Permission evaluation in the repository follows a "most specific denial wins" principle. If there are other policies elsewhere in the inheritance chain that deny access, they might be taking precedence.
  • The content structure in /libs is often protected by other ACLs higher in the hierarchy that your overlay doesn't override.
  • The AEM console UI might use additional permission checks beyond just reading the node structure.

Here's a step-by-step solution that addresses these potential issues:

  • Create your overlay: Make sure your overlay structure matches exactly and is in the correct location like /apps/cq/core/content/tools/your-custom-tool
  • At the specific tool node (not at the parent level), create a complete ACL structure:

 

/apps/cq/core/content/tools/your-custom-tool
    + rep:policy (nt:unstructured)
        + allow-specific-group (rep:GrantACE)
            - rep:principalName = "your-group-name"
            - rep:privileges = ["jcr:read", "jcr:readAccessControl"]
        + deny-everyone (rep:DenyACE)
            - rep:principalName = "everyone"
            - rep:privileges = ["jcr:read"]
            - rep:glob = "*"

 

  • Make sure your overlay uses a custom resource type:

 

/apps/cq/core/content/tools/your-custom-tool
    - sling:resourceType = "/apps/your-project/components/tools/your-custom-tool"

 

  • Youc could also add a security check in the component's JSP/HTL, something like:

 

// In your component's servlet or HTL helper class
ResourceResolver resolver = request.getResourceResolver();
boolean hasAccess = resolver.getUserID().equals("admin") || 
                   resolver.isUserMember("your-group-name");
if (!hasAccess) {
    response.sendError(HttpServletResponse.SC_FORBIDDEN);
    return;
}

 

 

Besides, if you're still experiencing issues, you can use the ACS AEM Commons ACL Packager tool to export and inspect the effective permissions.

 

Hope this helps!

 

Avatar

Level 9

Hi @Prince_Shivhare 

 

Maybe instead of /libs/cq/core/content/tools, you can overlay directly /libs/cq/core/content/nav/tools.

Then use granite:rendercondition to control the access for specific tool of your choice.
After you export the /apps/cq/core/content/nav/tools from AEM you will see an xml similar with the one below:

 

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
          xmlns:granite="http://www.adobe.com/jcr/granite/1.0"
          xmlns:jcr="http://www.jcp.org/jcr/1.0"
          xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
          jcr:primaryType="nt:unstructured">
    <tools
        jcr:primaryType="nt:unstructured"
        jcr:title="Tools"
        id="cq-tools"
        order="{Long}200">
        <workflow jcr:primaryType="nt:unstructured">
            <granite:rendercondition
                jcr:primaryType="nt:unstructured"
                sling:resourceType="/apps/my-project/.../my-condition" />
        </workflow>  
        .....
        <general
            jcr:primaryType="nt:unstructured"
            sling:orderBefore="workflow">
            <crxdelite
                jcr:primaryType="nt:unstructured">
                <granite:rendercondition
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="/apps/my-project/.../my-condition" />
            </crxdelite>
            .....
            <my-tool
                jcr:primaryType="nt:unstructured">
                <granite:rendercondition
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="/apps/my-project/.../my-condition" />
            </my-tool>
        </general>
        <cloudservices jcr:primaryType="nt:unstructured">
            <granite:rendercondition
                jcr:primaryType="nt:unstructured"
                sling:resourceType="/apps/my-project/.../my-condition" />
        </cloudservices>
    </tools>
</jcr:root>

 

I have not added the entire XML, I only kept few of the Tools available ootb just for you to get an idea. In addition I added one called my-tool, which might be your tool there.

 

In this way you can control access to any tool, custom or ootb one, by adding granite:condition. You can see it points to /apps/my-project/.../my-condition, which will be a custom resource backed-up by a Sling model:

 

Tethich_0-1740410714752.png

 

And in the Sling model you can implement your logic to decide whether the current logged in user should have access or not to the given tool.


So you can get the Authorizable from the resource resolver.

 

...
final Session session = resourceResolver.adaptTo(Session.class);
final UserManager userManager = resourceResolver.adaptTo(UserManager.class);
userManager.getAuthorizable(session.getUserID()
...

 

And then use existing API to find maybe in which group this Authorizable is and based on the group decide if it should have access or not to the tool: https://developer.adobe.com/experience-manager/reference-materials/6-4/javadoc/org/apache/jackrabbit...

I would not worry about performance as this is probably mainly for Editors within the company, so they should not put that much of a request load on AEM. Plus, we are talking only about author tier/instance, so live site is not impacted.

Avatar

Employee Advisor

I would also recommend to use renderconditions, but instead of rolling your own rendercondition in the first place, you can use the ootb renderconditions, see https://developer.adobe.com/experience-manager/reference-materials/6-5/granite-ui/api/jcr_root/libs/...and https://developer.adobe.com/experience-manager/reference-materials/6-5/granite-ui/api/jcr_root/libs/...

Avatar

Community Advisor

Hey Everyone,
Thanks for your answers. I'll try to implement your suggestion and will update this post accordingly.
Thank you