In Adobe Experience Manager (AEM), some pages are public (accessible to everyone), while others are secured (restricted to certain users). By default, the Dispatcher stores all pages—both public and secured—but it doesn’t check who should see them. This means that even secured pages could be displayed to unauthorized or anonymous users, which poses a security risk.
Permission-sensitive caching enables you to cache secured pages. Dispatcher checks the user’s access permissions for a page before delivering the cached page.
The Dispatcher integrates the AuthChecker module, which enables permission-sensitive caching. When activated, this module triggers an AEM servlet to verify the user’s authentication and authorization for the requested content. Based on the servlet’s response, the Dispatcher decides whether to serve the content from the cache or not.
Implementing permission-sensitive caching
- Create the Auth Checker servlet:
Create and deploy a servlet that performs authentication and authorization for the user requesting web content and sends a response Header.
The servlet obtains the session object and uses the checkPermission method to determine the appropriate response code.
import java.security.AccessControlException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This servlet will validate that the requested page uri is accessible or not and then accordingly set the response header.
*
*/
@Component( service = Servlet.class,
property = { sling.servlet.methods= "HEAD", sling.servlet.resourceTypes = "sling/servlet/default” sling.servlet.selectors = {"pagePermission"}, sling.servlet.extensions = {"getPermission"})
public class AuthcheckerServlet extends SlingSafeMethodsServlet {
/** The Constant LOGGER. */
private static final Logger logger = LoggerFactory.getLogger(AuthcheckerServlet.class);
/**
* Method to handle the HEAD request for the servlet.
*
* @param request - The request object.
* @param response - The response object.
*
*/
@Override
public void doHead(SlingHttpServletRequest request, SlingHttpServletResponse response) {
logger.debug("Start of doHead Method");
// retrieve the requested URL
String uri = request.getParameter("uri");
uri = uri.replace(HTML, EMPTY);
// obtain the session from the request
Session session = request.getResourceResolver().adaptTo(javax.jcr.Session.class);
if (session != null) {
try {
// perform the permissions check
session.checkPermission(uri, Session.ACTION_READ);
response.setStatus(SlingHttpServletResponse.SC_OK);
} catch (AccessControlException | RepositoryException e) {
response.setStatus(SlingHttpServletResponse.SC_FORBIDDEN);
}
}
else {
response.setStatus(SlingHttpServletResponse.SC_FORBIDDEN);
}
logger.debug("End of doHead Method");
}
}
- Configure Dispatcher for permission-sensitive caching:
The auth_checker section of the dispatcher.any file controls the behavior of permission-sensitive caching. Add this code to the publish-farm. The auth_checker section includes the following subsections:
- URL: The URL of the servlet that performs the security check.
- filter: To specify specific folders on which permission-sensitive caching is applied.
- headers: Specifies the HTTP headers that the Authorization Servlet includes in the response.
/auth_checker
{
# request is sent to this URL with '?uri=<page>' appended
/url "/content.pagePermission.getPermission"
# only the requested pages matching the filter section below are checked, all other pages get delivered unchecked
/filter
{
/0000
{
/glob "*"
/type "deny"
}
/0001
{
/glob "/content/we-retail/secure-pages/*.html"
/type "allow"
}
}
# any header line returned from the auth_checker's HEAD request matching the section below will be returned as well
/headers
{
/0000
{
/glob "*"
/type "deny"
}
/0001
{
/glob "Set-Cookie:*"
/type "allow"
}
}
}
Also, ensure that ‘allowAuthorized’ is set to 1 under the cache configuration.
/cache
{
...
allowAuthorized “1”
...
}
References: https://experienceleague.adobe.com/en/docs/experience-manager-dispatcher/using/configuring/permissions-cache