Adobe Experience Manager is designed to cater for content authoring of multiple sites by multiple content authors. Naturally, this process needs to be governed by strict Access Control Lists (ACLs) to manage who is allowed to do what at any given time. In this post, I’ll cover various approaches that can be used to manage authorizables and ACLs in AEM that should help you make a more informed decision when picking a permissions management strategy for your next project.

Basics of Roles and Permissions

Before we get started, we need to cover some basic terminology of permissions management in AEM. Throughout this post, I will refer to Users, Groups, Authorizables and Permissions quite a lot so let’s make sure we’re all on the same page.

A user is a unique account that is used to log in to the system and holds basic details such as name, password, email, etc. They may be part of multiple groups and can also hold their own privileges (although that’s not recommended).

A group is a collection of users whose primary purpose is to apply access rights to those users based on a particular role. AEM comes with a set of out-of-the-box groups but it’s suggested to create groups to fit a given organisation’s content authoring processes.

Permissions are used to identify who is allowed to do what on a given resource and are the result of evaluating Access Control Lists.

Now that we’re covered that off, we can get to the crux of this post and evaluate different ways of creating users, groups and their associated permissions. I like to always keep in mind maintainability, scalability and ease of use when assessing these sorts of strategies.

The ACL and Authorizable Packagers

Several companies use a combination of ACS Commons’ pre-defined package definitions (a.k.a Packagers) to manage their groups and ACLs. More specifically, the ACL Packager and the Authorizable Packager. This strategy is great to get something up and running quickly to manage roles and permissions. However, once the original packages are created from an accepted source of truth (usually production), they can become quite difficult to manage.

More often than not, permissions are tweaked to get a new feature working in a development environment and are never documented. This means the required permission changes never make their way to production due to a lack of communication. Add to this multiple development and staging environments and you can imagine how unwieldy this process becomes.

Moreover, content tends to differ between instances, which means package definitions may exist for content paths that do not exist. Due to the inflexible nature of content packages, this results in invalid content pages being created to inject policy nodes as depicted by the screenshots below.

 

Another issue with content packages is that the existing ACL entries on the target system remain untouched so there is never any clean-up of obsolete groups. The uncertainty in the contents of those packages leads teams to enter a stage where changing the package definition or re-building the package is avoided at all cost. For this approach to work, teams need to put in place strict role/permission change policies, document the roles and permissions, and communicate effectively any necessary changes so they can be properly managed.

Access Control Tool

An alternative approach that I have explored in the last year or so uses an excellent tool developed by Netcentric called AC Tool (a.k.a Access Control Tool). It allows developers to specify roles and permissions using YAML configuration files. The config is deployed as part of a standard CRX package and picked up by an installation hook which creates the relevant groups, ACLs and users.

What I love about this approach is that it’s self documenting, provides version history (as it’s managed through code) and ensures permissions are aligned across environments, because it cleans up existing ACLs of all roles managed by AC Tool.

configuration-file-structure

The great thing about adopting AC Tool is that it forces you to think carefully about how you architect your roles and permissions, thereby allowing your implementation to scale to multiple sites and roles with ease. Unlike traditional approaches where out of the box “blanket” rules are re-used, it encourages you to take a closer look at which roles are allowed to perform which actions, thereby hardening your platform.

To get started with AC Tool, I find it best to study their recommended best practice structure, use their real project example and customise it to your liking from there.

fragments.png

Something worth noting is that AC Tool encourages permissions to be broken up into reusable “fragments” to be used as building blocks. There is nothing special about fragments, they are just like normal groups that contain the minimum number of entries necessary to achieve the desired outcome.

A file organisation that has worked well for me is (please note that this example is not complete for readability purposes):

/apps/acls
 
  /config
    /fragments-content.yaml
    /fragments-functional.yaml
    /fragments-global.yaml
    /global.yaml
    /obsolete.yaml
    /roles.yaml
  /config.dev
    /users-acme.yaml

global.yaml
This file is used to set global AC Tool properties like the minimum version required or how to handle relationships with groups managed outside of the tool.

- global_config:

    minRequiredVersion: 2.0.1

obsolete.yaml
This configuration contains authorizables that should be cleaned up from a target system on install. This is handy for cleaning up legacy users and groups that are not applicable with the new configuration.

- obsolete_authorizables:

    - some-legacy-group

fragments-global.yaml
This configuration contains the global permission fragments that are used to form the basis of the other functional fragments. This permissions in this file should be customised based on your requirements but can largely be based off the Netcentric’s real world example. Note: The “DEF” keyword defines a variable to be used within the configuration file.

- DEF fragmentPath="global/fragments"

- group_config:

    - fragment-basic-allow:

        - name:
          memberOf:
          path: ${fragmentPath}

    - fragment-restrict-for-everyone:

        - name:
          memberOf:
          path: ${fragmentPath}


- ace_config:

    - fragment-basic-allow:

        - path: /
          permission: allow
          actions: read
          privileges:
          repGlob:

        - path: /etc
          permission: allow
          actions:
          privileges: jcr:read,jcr:readAccessControl
          repGlob: ""


    - fragment-restrict-for-everyone:

        - path: /
          permission: allow
          actions: read
          privileges:
          repGlob:

        - path: /content
          permission: deny
          actions:
          privileges: jcr:read,jcr:readAccessControl
          repGlob:

When using the Netcentric example, it’s worth noting that the configured deny ACLs may not apply to your version of AEM as navigation paths may have changed.

fragments-functional.yaml
This configuration contains only the permissions necessary to access various UI functionality not specific to any project. For example, having the ability to access the DAM view but not the ability to modify the contents of the DAM.
Breaking permissions up between content and functionality allows for greater reuse and flexibility when making up roles for the organisation. I recommend creating generic functional fragments (i.e. tagging, commerce, user admin, etc) and then creating role fragments that might make up one or more functional fragments (i.e. contentmanager, poweruser).

- DEF fragmentPath="global/fragments"

- group_config:

    - fragment-siteadmin:

        - name:
          memberOf:
          path: ${fragmentPath}

    - fragment-dam:

        - name:
          memberOf:
          path: ${fragmentPath}

- ace_config:

    - fragment-siteadmin:

        - path: /libs/wcm/core/content/siteadmin
          permission: allow
          actions: read
          privileges:
          repGlob:

        - path: /libs/cq/core/content/nav/sites
          permission: allow
          actions: read
          privileges:
          repGlob:

    - fragment-dam:

        - path: /libs/wcm/core/content/damadmin
          permission: allow
          actions: read
          privileges:
          repGlob:

        - path: /libs/cq/core/content/nav/assets
          permission: allow
          actions: read
          privileges:
          repGlob:

fragments-content.yaml
This configuration contains only the permissions necessary to access various content specific to a particular site or business unit. Note: the “FOR-IN” is a loop syntax to iterate through a set of values specified in the array.

- group_config:

    - FOR brand IN [ brandA, brandB, brandC ]:

        - content-${brand}:

            - name:
              memberOf:
              path: ${brand}/fragments

        - dam-${brand}:

            - name:
              memberOf:
              path: ${brand}/fragments

- ace_config:

    - FOR brand IN [ brandA, brandB, brandC ]:

        - content-${brand}:

            - path: /content/${brand}
              permission: allow
              actions: read,modify,create,delete,acl_read,replicate
              privileges:
              repGlob:

        - dam-${brand}:

            - path: /content/dam/${brand}
              permission: allow
              actions: read,modify,create,delete,acl_read,replicate
              privileges:
              repGlob:

roles.yaml
This configuration is used to create the various roles that users will be assigned to. It’s in this file that functional fragments will be matched up with content fragments. In other words, it’s the location where the ability to access a feature in AEM will be matched up with the ability to modify project content. It’s also a situation where looping through the managed brands is very useful (provided that each project has similar authoring requirements).

- group_config:

    - FOR brand IN [ brandA, brandB, brandC ]:

        - ${brand}-authors:

            - name:
              memberOf: fragment-contentmanager,content-${brand},dam-${brand}
              path: ${brand}

        - ${brand}-publishers:

            - name:
              memberOf: fragment-poweruser,content-${brand},dam-${brand}
              path: ${brand}

users-acme.yaml
While this is purely optional, I find it useful to setup test users in development environments especially when dealing with workflows. As a developer, it removes the hassle of creating the user(s) manually and it’s always good to check that a feature being developed works with the intended end user (instead of working with admin rights).

- DEF basePath="test"

- user_config:

    - test-author:

        - name: test-author
          memberOf: brandA-authors
          password: password
          path: ${basePath}

    - test-publisher:

        - name: test-publisher
          memberOf: brandA-publishers
          password: password
          path: ${basePath}

It’s possible to create system (a.k.a service) users via AC Tool but depending on how your code base makes use of them, you may want to have a configuration file dedicated to the creation of those users (i.e. “users-system.yaml”).

As far as downsides are concerned, the only thing I can think of is that AC Tool needs to be installed only once prior to the config files being installed. If you were thinking of installing AC Tool as a sub package of the package containing your ACLs, this is currently not possible as it’s designed to be installed only once per AEM instance. The hook provided by the application will not exist at the time the config package is installing so no authorizables will be generated. As a result, this makes it quite difficult to update to a newer version and in more mature cloud environments, this means it needs to be installed in the instance provisioning process.

Due to the use of fragments to build up group permissions, the use of this tool tends to generate an excessive amount of groups. It’s for this reason that I would recommend bundling all the brand-specific fragments into corresponding folders like so:

/home/groups
  /brandA
    brandA-authors
    brandA-publishers
    /fragments
      dam-brandA
      content-brandA
  /brandB
    brandB-authors
    brandB-publishers
    /fragments
      dam-brandB
      content-brandB

Whilst this is all good for greenfield AEM projects, mature organisations may find it difficult to move to such a model unless their existing permission matrix has been well documented in advance. In the case it hasn’t, a “dump” of ACLs and authorizables could be taken using the AC Tool JMX beans but this will not output YAML configuration that is considered best practice, thereby curbing the benefits of adopting AC Tool in the first place.

Conclusion

Permissions management is a tricky problem to solve in any web content management system where content is ever changing. In my opinion, AC Tool currently provides the best solution due to its powerful syntax that can be leveraged to create the most complex policies, its documented best practices and more importantly the guarantee it provides that permissions will be consistent across environments.

 

Written by Michael Leroy

Consultant at Shine Solutions and Adobe Certified AEM Lead Developer

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s