Published on

AEM Dispatcher Series 3 - Securing Your AEM Site - Deep Dive into Dispatcher `/filter` Rules

Authors

If you’ve been following along, you now understand the role of the AEM Dispatcher and how its dispatcher.any file is structured.

In this post, we’ll focus on one of the most critical parts of that file — the /filter section.

This is the Dispatcher’s security gate — the rulebook that decides which requests are allowed to reach AEM and which are denied at the door.

Why /filter Rules Matter

If you’re an AEM developer, you’ve probably heard something like:

  • “I can’t access my servlet.”
  • “I’m getting a 403 Forbidden.”
  • “Why can’t I hit /system/console on Publish?”

Nine times out of ten, the answer lies in the Dispatcher’s /filter section.

Even though DevOps or AMS teams often maintain these files, understanding filters is vital for developers because:

  • You’ll need to safely expose custom endpoints like /bin/my-servlet.
  • You’ll debug 403 Forbidden errors during testing.
  • You’ll collaborate better with ops teams by explaining what your code needs access to.

Understanding How /filter Works

Dispatcher filters act as allowlists or denylists for incoming HTTP requests. They determine what URLs are allowed to pass through to AEM Publish or Author.

At a high level:

  • Each rule has a /type — either "allow" or "deny".
  • Each rule has a /url (and optionally /method) pattern that it applies to.
  • Dispatcher evaluates rules in order, from top to bottom.

If a request matches a rule, that rule decides whether to allow or deny it. Once a match is found, Dispatcher stops evaluating further rules.

Default Behavior: Deny or Allow?

Dispatcher has no true default allow. If a URL does not explicitly match an allow rule, it is effectively denied.

This default-deny model is intentional. You explicitly allow only what is safe.

Example: A Simple /filter Section

/filter {
  /0001 { /type "deny"  /url "/crx/*" }
  /0002 { /type "deny"  /url "/system/console/*" }
  /0003 { /type "allow" /url "/content/*" }
  /0004 { /type "allow" /url "/etc.clientlibs/*" }
  /0005 { /type "allow" /url "/content/dam/*" }
  /0006 { /type "allow" /url "/dispatcher/invalidate.cache" }
  /0007 { /type "allow" /url "/libs/granite/core/content/login.html" }
}

How it works:

  1. Requests to /crx/* or /system/console/* are denied.
  2. Regular website content under /content/ is allowed.
  3. Client libraries and DAM assets are allowed.
  4. Special endpoints for cache invalidation or login are allowed.

Real-World Example: Allowing a Custom Servlet

Suppose you have a custom path based servlet at /bin/my-servlet. It works on Author, but on Publish you get 403 Forbidden.

This is because /bin/* is not allowed by default. To fix it, add an allow rule.

Step 1: Add the rule

/filter {
  ...
  /0050 { /type "allow" /url "/bin/my-servlet" }
}

Step 2: Restrict it if needed

If the servlet is for authenticated users or internal use, restrict by method:

/filter {
  ...
  /0050 {
    /type "allow"
    /url "/bin/my-servlet"
    /method "POST"
  }
}

Only POST requests are allowed; GET requests are denied.

Example: Allowing a JSON Endpoint Safely

Suppose you have a component that fetches JSON data from /content/mysite/en/home.model.json.

If you get 403, explicitly allow .model.json requests:

/filter {
  ...
  /0060 { /type "allow" /url "*.model.json" }
}

Avoid overly broad patterns like /*.json which could expose sensitive endpoints.

Example: Denying Access to AEM Consoles

Blocking access to administrative paths is critical. A recommended set of deny rules:

/filter {
  /0001 { /type "deny" /url "/crx/*" }
  /0002 { /type "deny" /url "/system/console/*" }
  /0003 { /type "deny" /url "/libs/granite/*" }
  /0004 { /type "deny" /url "/apps/*" }
  /0005 { /type "deny" /url "/bin/querybuilder.json" }
  /0006 { /type "deny" /url "/conf/*" }
}

These prevent access to internal tooling and administrative APIs.

Dispatcher processes /filter rules in numerical order, typically /0001, /0002, /0003, etc.

If you add a new rule, ensure it does not override or conflict with existing ones.

For example:

  • If /0002 denies /content/* but /0003 allows /content/mysite/*, /0002 blocks everything before /0003 can allow it.

Always order rules carefully, placing specific allows before broader denies when needed.

Debug Tip: Logging and Testing Filters

  1. Enable Dispatcher debug logging in Apache configuration:
DispatcherLogLevel 3
  1. Check dispatcher.log for entries:
Filtering URI '/bin/my-servlet' - denied
Filtering URI '/content/mysite/en.html' - allowed
  1. Test your updated /filter rules in a lower environment before production.

Key Takeaways for Developers

  • The /filter section is your security gate.
  • Dispatcher uses a default-deny model — only explicitly allowed paths are permitted.
  • Always write specific rules, never broad wildcards like / or /*.json.
  • Order matters — rules are evaluated top to bottom.
  • Understanding filters helps you quickly fix 403 and access issues.

Next: Part 4 — A Developer’s Guide to Dispatcher /cache Rules