Service Users in AEM
- Topics:
- Security
CREATED FOR:
- Admin
Overview
The main way of getting an administrative session or resource resolver in AEM was using the SlingRepository.loginAdministrative()
and ResourceResolverFactory.getAdministrativeResourceResolver()
methods provided by Sling.
However, neither of these methods were designed around the principle of least privilege and make it too easy for a developer not to plan for a proper structure and corresponding Access Control Levels (ACLs) for their content early on. If a vulnerability is present in such a service it often leads to privilege escalations to the admin
user, even if the code itself would not need administrative privileges to work.
How to Phase Out Admin Sessions
Priority 0: Is the feature active/needed/derelict?
There may be cases where the admin session is not used, or the feature is disabled entirely. If this is the case with your implementation, make sure you remove the feature altogether or fit it with NOP code.
Priority 1: Use The Request Session
Whenever possible refactor your feature so that the given, authenticated request session can be used for reading or writing content. If this is not doable, it can often be achieved by applying the priorities following the ones below.
Priority 2: Restructure Content
Many issues can be resolved by restructuring the content. Keep these simple rules in mind when doing the restructure:
-
Change access control
- Make sure that the users or groups that really need access actually have access;
-
Refine content structure
- Move it to other locations, for example where access control matches the request sessions available;
- Change the content granularity;
-
Refactor your code to be a proper service
- Move the business logic from JSP code to service. This allows different content modelling.
Also, make sure that any new features you develop adhere to these principles:
-
Security requirements should drive the content structure
- Managing access control should feel natural
- Access control must be enforced by the repository, not the application
-
Make use of nodetypes
- Restrict the set of properties that can be set
-
Respect privacy settings
- In the case of private profiles, one example would be to not expose the profile picture, email or full name found on the private
/profile
node.
- In the case of private profiles, one example would be to not expose the profile picture, email or full name found on the private
Strict Access Control
Whether you apply access control while restructuring content or when you do it for a new service user, you must apply the strictest ACLs possible. Use all possible facilities of access control:
-
For example, instead of applying
jcr:read
on/apps
, only apply it to/apps/*/components/*/analytics
-
Use restrictions
-
Apply ACLs for node types
-
Limit permissions
- for example, when only needing to write properties, do not give the
jcr:write
permission; usejcr:modifyProperties
instead
- for example, when only needing to write properties, do not give the
Service Users and Mappings
If the above fails, Sling 7 offers a Service User Mapping service, which allows to configure a bundle-to-user mapping and two corresponding API methods: [SlingRepository.loginService()](https://sling.apache.org/apidocs/sling7/org/apache/sling/jcr/api/SlingRepository.html#loginService-java.lang.String-java.lang.String-)
and [ResourceResolverFactory.getServiceResourceResolver()](https://sling.apache.org/apidocs/sling7/org/apache/sling/api/resource/ResourceResolverFactory.html#getServiceResourceResolver-java.util.Map-)
which return a session/resource resolver with the privileges of a configured user only. These methods have the following characteristics:
-
They allow mapping services to users
-
They make it possinle to define sub-service users
-
The central configuration point is:
org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl
-
service-id
=service-name
[ “:” subservice-name ] -
service-id
is mapped to a resource resolver and/or JCR repository user ID for authentication -
service-name
is the symbolic name of the bundle providing the service
Other Recommendations
Replacing the admin-session with a service-user
A service user is a JCR user with no password set and a minimal set of privileges that are necessary to perform a specific task. Having no password set means that it will not be possible to login with a service user.
A way to deprecate an administrative session is to replace it with service user sessions. It could also be replaced by multiple sub-service users if needed.
To replace the admin session with a service user, you should perform the following steps:
-
Identify the necessary permissions for your service, keeping the principle of least permission in mind.
-
Check if there is already a user available with exactly the permission setup you need. Create a new system service user if no existing user matches your needs. RTC is needed to create a new service user. Sometimes, it makes sense to create multiple sub-service users (for example, one for writing and one for reading) to compartmentalize access even more.
-
Setup and test ACEs for your user.
-
Add a
service-user
mapping for your service and foruser/sub-users
-
Make the service user sling feature available to your bundle: update to the most recent version of
org.apache.sling.api
. -
Replace the
admin-session
in your code with theloginService
orgetServiceResourceResolver
APIs.
Creating a new service user
After you verified that no user in the list of AEM service users is applicable for your use case and the corresponding RTC issues have been approved, you can go ahead and add the new user to the default content.
The recommended approach is to create a service user to use the repository explorer at https://<server>:<port>/crx/explorer/index.jsp
The goal is to get a valid jcr:uuid
property which is mandatory in order to create the user via a content package installation.
You can create service users by:
-
Going to the repository explorer at https://<server>:<port>/crx/explorer/index.jsp
-
Logging in as admin by pressing the Log In link in the upper left corner of the screen.
-
Next, create and name your system user. In order to create the user as a system one, set the intermediate path as
system
and add optional subfolders depending on your needs: -
Verify that your system user node looks as follows:
NOTE
Note that there are no mixin types associated with service users. This means that there will be no access control policies for system users.
When adding the corresponding .content.xml to the content of your bundle, make sure you have set the rep:authorizableId
and that the primary type is rep:SystemUser
. It should look like this:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="https://www.jcp.org/jcr/1.0" xmlns:rep="internal"
jcr:primaryType="rep:SystemUser"
jcr:uuid="4917dd68-a0c1-3021-b5b7-435d0044b0dd"
rep:principalName="authentication-service"
rep:authorizableId="authentication-service"/>
Adding a configuration amendment to the ServiceUserMapper configuration
To add a mapping from your service to the corresponding System Users you need to create a factory configuration for the [ServiceUserMapper](https://sling.apache.org/apidocs/sling7/org/apache/sling/serviceusermapping/ServiceUserMapper.html)
service. To keep this modular such configurations can be provided using the Sling amend mechanism. The recommended way to install such configurations with your bundle is by using Sling Initial Content Loading:
-
Create a subfolder SLING-INF/content below the src/main/resources folder of your bundle
-
In this folder create a file named org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-<some unique name for your factory configuration>.xml with the content of your factory configuration (including all sub-service user mappings). Example:
-
Create a
SLING-INF/content
folder below thesrc/main/resources
folder of your bundle; -
In this folder create a file
named org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-<a unique name for your factory configuration>.xml
with the content of your factory configuration, including all sub-service user mappings.For illustration purposes, take a the file called
org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-com.adobe.granite.auth.saml.xml
:<?xml version="1.0" encoding="UTF-8"?> <node> <primaryNodeType>sling:OsgiConfig</primaryNodeType> <property> <name>user.default</name> <value></value> </property> <property> <name>user.mapping</name> <values> <value>com.adobe.granite.auth.saml=authentication-service</value> </values> </property> </node>
-
Reference the Sling initial content in the configuration of the
maven-bundle-plugin
in thepom.xml
of your bundle. Example:<Sling-Initial-Content> SLING-INF/content;path:=/libs/system/config;overwrite:=true; </Sling-Initial-Content>
-
Install your bundle and make sure the factory configuration has been installed. You can do this by:
- Going to the Web Console at https://serverhost:serveraddress/system/console/configMgr
- Search for Apache Sling Service User Mapper Service Amendment
- Click the link to see if the proper configuration is in place.
Dealing with shared sessions in services
Calls to loginAdministrative()
often appear together with shared sessions. These sessions are acquired on service activation and are only logged out after the service is stopped. Although this is common practice, it leads to two problems:
- Security: Such admin sessions are used to cache and return resources or other objects that are bound to the shared session. Later in the call stack these objects could get adapted to sessions or resource resolvers with elevated privileges, and often it is not clear to the caller that it is an admin session they are operating with.
- Performance: In Oak shared sessions can cause performance problems, and it is currently not recommended to use them.
The most obvious solution for the security risk is to simply replace the loginAdministrative()
call with a loginService()
one to a user with restricted privileges. However, this will not have any impact on any potential performance degradation. A possibility to mitigate that is to wrap all requested information in an object that has no association with the session. Then, create (or destroy) the session on demand.
The recommended approach is to refactor the service’s API to give the caller control over the creation/destruction of the session.
Administrative sessions in JSPs
JSPs cannot use loginService()
, because there is no associated service. However, administrative sessions in JSPs are usually a sign of a violation of the MVC paradigm.
This can be fixed in two ways:
- Restructuring the content in a way that allows manipulating it with the user session;
- Extracting the logic to a service that provides an API that can then be used by the JSP.
The first method is the preferred one.
Processing Events, Replication Preprocessors and Jobs
When processing events or jobs, and in some cases workflows, the corresponding session that triggered the event is usually lost. This leads to event handlers and job processors often using administrative sessions to do their work. There are different conceivable approaches to solve this problem, each with their advantages and disatvantages:
-
Pass the
user-id
in the event payload and use impersonation.Advantages: Easy to use.
Disadvantages: Still uses
loginAdministrative()
. It re-authenticates a request that has already been authenticated. -
Create or reuse a service user that has access to the data.
Advantages: Consistent with the current design. Needs minimal change.
Disadvantages: Needs very powerful service users to be flexible, which can easily lead to privilege escalations. Circumvents the security model.
-
Pass a serialization of the
Subject
in the event payload, and create aResourceResolver
based on that subject. One example would be using the JAASdoAsPrivileged
in theResourceResolverFactory
.Advantages: Clean implementation from a security standpoint. It avoids re-authentication and it operates with the original privileges. Security relevant code is transparent to the consumer of the event.
Disadvantages: Needs refactoring. The fact that the security relevant code transparent to the consumer of the event might also lead to problems.
The third approach is currently the preferred processing technique.
Workflow Processes
Within workflow process implementations the corresponding user session that triggered the workflow is usually lost. This leads to workflow processes often using administrative sessions to perform their work.
In order to fix these issues, it is recommended that the same approaches mentioned in Processing Events, Replication Preprocessors and Jobs be used.
Sling POST Processors and Deleted Pages
There are a couple of administrative sessions used in sling POST processor implementations. Usually, administrative sessions are used to access nodes that are pending deletion within the POST being processed. In consequence, they are no longer available via the request session. A node pending deletion may be accessed to disclose metada that otherwise should not be accessible.
Experience Manager
- Administering User Guide overview
- Sites Features
- Website Administration
- Reusing Content: Multi Site Manager and Live Copy
- Live Copy Overview Console
- Configuring Live Copy Synchronization
- Creating and Synchronizing Live Copies
- MSM Rollout Conflicts
- MSM Best Practices
- Translating Content for Multilingual Sites
- Managing Translation Projects
- Identifying Content to Translate
- Preparing Content for Translation
- Creating a Language Root Using the Classic UI
- Connecting to Microsoft Translator
- Configuring the Translation Integration Framework
- Language Copy Wizard
- Translation Enhancements
- Translation Best Practices
- Configurations and the Configuration Browser
- AEM FAQs
- Operations
- Dashboards
- Operations Dashboard
- Backup and Restore
- Data Store Garbage Collection
- Monitoring Server Resources Using the JMX Console
- Working with Logs
- Configure the Rich Text Editor
- Configure the Video component
- The Bulk Editor
- Configuring Email Notification
- Configuring RTE for Producing Accessible Sites
- The Link Checker
- Troubleshooting AEM
- Audit Log Maintenance in AEM 6
- Editor
- Managing Access to Workflows
- Using cURL with AEM
- Configuring Undo for Page Editing
- Proxy Server Tool (proxy.jar)
- Configuring for AEM Apps
- Administering Workflows
- Configuring Search Forms
- Tools Consoles
- Reporting
- Administering Workflow Instances
- Configuring Layout Container and Layout Mode
- Enabling Access to Classic UI
- Starting Workflows
- Configure the Rich Text Editor plug-ins
- Admin Consoles
- Security
- User Administration and Security
- User, Group and Access Rights Administration
- Security Checklist
- OWASP Top 10
- Running AEM in Production Ready Mode
- Identity Management
- Adobe IMS Authentication and Admin Console Support for AEM Managed Services
- Creating a Closed User Group
- Mitigating serialization issues in AEM
- User Synchronization
- Encapsulated Token Support
- Single Sign On
- How to Audit User Management Operations in AEM
- SSL By Default
- SAML 2.0 Authentication Handler
- Closed User Groups in AEM
- Granite Operations - User and Group Administration
- Enabling CRXDE Lite in AEM
- Configuring LDAP with AEM 6
- Configure the Admin Password on Installation
- Service Users in AEM
- Encryption Support for Configuration Properties
- Handling GDPR Requests for the AEM Foundation
- Content Disposition Filter
- Personalization
- eCommerce
- Integration
- Integrating with Third-Party Services
- Integrating with Salesforce
- Integrating with Adobe Target
- Integrating with Adobe Analytics
- Connecting to Adobe Analytics and Creating Frameworks
- Configuring Link Tracking for Adobe Analytics
- Mapping Component Data with Adobe Analytics Properties
- Configuring Video Tracking for Adobe Analytics
- HTTP2 Delivery of Content FAQ
- Troubleshooting your Adobe Campaign Integration
- SharePoint Connector Licenses, Copyright Notices, and Disclaimers
- SharePoint Connector
- DHTML Viewer End-of-Life FAQs
- Integrating with Adobe Campaign Classic
- Related Community Articles
- Integrating with Adobe Campaign Standard
- Flash Viewers End-of-Life Notice
- Integrating with Adobe Creative Cloud
- Integrating with Adobe Dynamic Tag Management
- Opting Into Adobe Analytics and Adobe Target
- AEM Portals and Portlets
- Integrating with Dynamic Media Classic
- Troubleshooting Integration Issues
- Integrating with BrightEdge Content Optimizer
- Best Practices for Email Templates
- Catalog Producer
- Integrating with Silverpop Engage
- Integrating with Adobe Campaign
- Integrating with ExactTarget
- Analytics with External Providers
- Integrating with the Adobe Marketing Cloud
- Manually Configuring the Integration with Adobe Target
- Prerequisites for Integrating with Adobe Target
- Adobe Classifications
- Solutions Integration
- Target Integration with Experience Fragments
- Best Practices
- Content Management