Aug 22, 2023
In this article, we will cover how to create a Service User (SU) and grant privileges using Sling Repository Initializer (SRI).
AEM Version: AEM 6.5.4+ and AEM as a Cloud Service
Concepts to Know
Sling Repository Initializer (SRI) factory allows you to run code before the SlingRepository service is registered, ensuring the ideal state and structure of the repository before its first usage/access.
It can create paths, users, groups, assign users to groups and provide privileges and restrictions. This option is recommended to create your users and groups from AEM 6.5.4+ and is compatible with AEM as a Cloud Service.
Service Users (SU) (aka System Users) are special JCR users that require no password to authenticate into the system. They expect to be assigned only the privileges required to perform a specific task, thus following the principle of least privilege. This option has been provided since AEM 6.0 for Back End services to get the corresponding permissions required to access the repository and AEM environment.
Creating a Service User with Required Privileges.
There are two ways to create a SU:
-
From the CRX Explorer→ User Administration→ Create System User, enter the user name, then go to User Administration and assign the corresponding permissions to that new service user. This approach was the most popular for some time but there are a couple of drawbacks:
-
It requires too much human interaction since administrators must create users at least once in every environment where the system is deployed.
-
It is not compatible with Adobe as a Cloud Service.
-
-
Using Sling Repository Initializer factory, which allows you to run code before the SlingRepository service is registered, ensuring a certain state and structure of the repository (you can create paths, users, groups, assign users to groups, and provide privileges and restrictions) before using/accessing it.
If you used the AEM Project Archetype to create your project, by default, an OOTB RI file is generated with a basic initialization script. In our example (oshynDemo project), this file is named:
Repo Init Config
org.apache.sling.jcr.repoinit.RepositoryInitializer~oshynDemo.cfg.json
and can be found at the root config directory at ui.config/src/main/content/jcr_root/apps/YOUR_SITE_PATH/osgiconfig/config/
, in our case:
Root Config Path
ui.config/src/main/content/jcr_root/apps/oshynDemo/osgiconfig/config/
as the Archetype deploys it by defect to all different RunModes. But you can place different RI files for the different RunModes in the system. This is the RI file auto-generated by the Archetype:
OOTB Repository Initializer
{
"scripts": [
"create path (sling:OrderedFolder) /content/dam/oshynDemo",
"create path (nt:unstructured) /content/dam/oshynDemo/jcr:content",
"set properties on /content/dam/oshynDemo/jcr:content\n set cq:conf{String} to /conf/oshynDemo\n set jcr:title{String} to \"Oshyn Demo\"\nend"
]
}
Configuration names are suggested by Adobe to be created on .cfg.json
file types but you can use .config
files as well.
Unfortunately, .json
files do not have good multiline support. However, a .config
file does have it and configurations tend to be multiline at times.That's why we prefer to use a .config file and our Service User definition looks like this:
org.apache.sling.jcr.repoinit.RepositoryInitializer-oshynDemo-service-users.config
scripts=["
create service user oshynDemo-replication-service-user with forced path system/cq:services/oshyn-demo
set principal ACL for oshynDemo-replication-service-user
allow jcr:versionManagement,jcr:read,crx:replicate,rep:write,jcr:lockManagement on /content/oshynDemo
allow jcr:versionManagement,jcr:read,crx:replicate,rep:write,jcr:lockManagement on /conf
allow jcr:read on /apps
end
"]
Please notice the differences between .cfg.json
and .config
notation. For example, in .config it is not required to wrap "scripts" definition into "{}" as has been done in .cfg.json
files.
This is how it finally looks in the project structure.
Important Details
-
Notice the file name always starts with the OOTB class name (
org.apache.sling.jcr.repoinit.RepositoryInitializer
) and after that, the required custom name can be added (dash separated). Also, for separation between the OOTB class name and your custom file name suffix, Adobe uses a "tilde" symbol (~) , but you can also use a dash(-). -
Service Users MUST be created under
system/cq:services
to be compatible with AEMaaCS (AEMaaCS supports principal-based authorization by default only for all users below/home/users/system/cq:services
). It is suggested to create a subfolder to group all possible Service Users required for the application (system/cq:services/oshyn-demo
). -
CRITICAL: You can't have both files(
.cfg.json
and.config
) in your project. You need to choose one way and use a single repo init factory file. (Do not deploy both files to your AEM server, as it may cause the repository to be in an inconsistent state next time the AEM instance starts. This gives a 503 error, leaving the site down and probably will require you to delete the repository and install a new AEM instance from scratch, losing any data not externally backed up). -
You should keep the initialization steps provided by the AEM Archetype. In such a case, you need to migrate the .cfg.json script to .config format. The following file shows the final result when completed:
org.apache.sling.jcr.repoinit.RepositoryInitializer-oshynDemo-service-users.config
scripts=["
create path (sling:OrderedFolder) /content/dam/oshynDemo
create path (nt:unstructured) /content/dam/oshynDemo/jcr:content
set properties on /content/dam/oshynDemo/jcr:content
set cq:conf{String} to /conf/oshynDemo
set jcr:title{String} to \"Oshyn Demo\"
end
create service user oshynDemo-replication-service-user with forced path system/cq:services/oshyn-demo
set principal ACL for oshynDemo-replication-service-user
allow jcr:versionManagement,jcr:read,crx:replicate,rep:write,jcr:lockManagement on /content/oshynDemo
allow jcr:versionManagement,jcr:read,crx:replicate,rep:write,jcr:lockManagement on /conf
allow jcr:read on /apps
end
"]
At this point, we have a Service User readily available. However it cannot be used by any OSGi Component yet, it needs to be mapped to a Service Identifier first using a ServiceUserMapper Configuration Amendment (SUMCA) factory. We cover this topic in our blog: AEM User Mappings: Enforcing Cybersecurity Through the Principle of Least Privilege.
Wrapping Up
Configuration files are the correct solution to define repository structure and systems behavior for situations like Service Users, general users, groups, permissions, repository structure, and configurations like the User Mappings. As these configurations are shipped within the code base and can be customized per environment, there's no need for manual processes. This approach removes the human error factor and allows your AEM environment to be set up for use from the first deployment iteration.
Related Insights
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.