• Juan Ayala

System Users in AEM 6.5 and AEMaaCS

In the old days, if you needed a Sling ResourceResolver, you would get a reference to a ResourceResolverFactory and call getAdministrativeResourceResolver(). Easy peasy.

For obvious reasons that function is now deprecated. Who thought it would be a good idea to give admin privileges to anyone who asked without some sort of check?!

Its successor is getServiceResourceResolver(). Unfortunately, it came with one pesky problem. We needed to create and manage system user accounts.

I will talk about some of the ways to create and manage these system accounts. I will end with the new and preferred way.

CRX Explorer

The first way to create a system user is through the CRX Explorer. You would do this on your local instance. Then assign ACL as needed. Once complete you would capture the changes with a content package. This package would be one of your deployment packages.

This was by far the hardest way to manage service users and permissions. It worked great the first time. Later updates and changes would get tricky.

NetCentric AC Tool

The second way to create a system user is with Netcentric's AC Tool. As far as features, it is way ahead of all the other options. For example, its export feature is great when migrating users and groups. It is great at removing obsolete entries because it keeps a history of your changes. And of course, its YAML configuration files are easy to read.

I would say that it is better suited for AEM 6.5 than AEMaaCS. Since AEMaaCS blocks the Felix Web Console, the AC Tool's JMX Console is not accessible. This makes it harder to troubleshoot.

There is also some configuration overhead. I spent a long time reading about install hooks and startup hooks and Oak indices. Just so I can set up one little service user account.

ACS Commons Ensure Authorizable

The third way to create a system user is with the Ensure Authorizable feature of ACS Commons. This was my preferred method for several years. It is dead simple. Install ACS Commons and create a EnsureServiceUser OSGi configuration. Nothing much to it.

You may have noticed this alert message at the top of the Ensure Authorizable page

AEM 6.3 and greater should migrate to [Sling Repo Init scripts]( to ensure Authorizables and ACLS. Sling Repo Init supports creation of Users, Service Users and Groups, as well as the application of ACLs. It is generally recommended to prefer principal-based ACLs over resource-based ACLs when using Repo Init.

If ACS Commons is saying we should use Repo Init, I say "What's good for the goose is good for the gander".

Sling Repository Initialization

If you have used the AEM Project Archetype recently you may have noticed an OSGi configuration file.

⚠️ The current version of the AEM project archetype I'm using is 30. If you are using this you may notice there are 2 Repo Init config files, a .json, and a .config.

  • /apps/mysite/osgiconfig/config/

  • /apps/mysite/osgiconfig/config/

PR #806 was already merged. In case you see the duplicates, delete the JSON file. For the repo init scripts JSON doesn't work well. JSON does not allow multi-line in the editor.

The repository initializer is available on the latest AEM6.5 and AEMaaCS. If you are using an older AEM version, check the version of the bundle. It should be v1.1.6+. Depending on the verison you may find some of the grammar works or doesn't. Either way, tail the logs. The errors are usually pretty self-explanatory.

Let's append this to the end of the RepositoryInitializer-mysite.config file

# create /content/mysite/blog
create path (sling:OrderedFolder) /content/mysite(cq:Page)/blog(cq:Page)/jcr:content(cq:PageContent)
set properties on /content/jm/jcr:content
    set jcr:title{String} to \"My Site Blog\"

# service user my-content-reader (path is relative)
create service user my-content-reader with path system/mysite
set ACL for my-content-reader
    allow jcr:read on /content/mysite/blog

First I created the path that I will be setting ACL on. If you are working on a local instance you may not notice until you deploy into a new environment where it will fail. This is also important on Cloud Manager pipelines during the Build Images phase. Those images will not have your content on them.

From this point on it is as before. You need to create a Service User Mapping via the OSGi configuration

  "user.mapping": [

Finally, get a resource resolver using mysiteReader as the Sling sub-service.

final Map<String, Object> authInfo =
        ImmutableMap.of(ResourceResolverFactory.SUBSERVICE, "mysiteReader");
try (ResourceResolver resolver =
        resourceResolverFactory.getServiceResourceResolver(authInfo)) {

    final Resource blog = resolver.getResource("/content/mysite/blog");"got {}", blog.getPath());

} catch (LoginException e){
    logger.error("could not open resource resolver", e);


The repository initialization modules have been around for a while. It wasn't until v1.1.6 back in early 2020 that the grammar began to change to support some of the features we see today. With AEMaaCS immutable instances this way of bootstrapping repositories will become more prevalent.

652 views0 comments

Recent Posts

See All