Filters
Java filters were introduced in the Java Servlet specification version 2.3. A filter intercepts requests and responses to transform or use the information. Filters typically don’t create responses themselves but instead provide universal functions that can be attached
to any type of servlet page.
Since the filter chain is responsible for request handling in Magnolia, the default chain illustrates how filters are used to process requests. This page provides minimal information on filters. For more information, see Request processing and filters and the filters
package.
Don’t change the filter order Magnolia handles incoming requests to display a page through its own filter chain. Filters in the chain are executed in the order in which they are declared until a filter decides that it can fulfill the request. Be careful When editing properties in the filter chain be careful. Always test the changes on test environment before applying it to production. For instance, if you add a info.magnolia.voting.Voter to a filter with an erroneous regular expression, you won’t be able to access AdminCentral anymore. In such a case, you have to use the Groovy Rescue app. |
Context
The first filter in the filter chain is the info.magnolia.cms.filters.ContextFilter. This filter initializes MgnlContext
and configures MDC logging. MgnlContext
is local to the request and available on every further filter. The context provides a lot of useful functions, see info.magnolia.context.MgnlContext for details.
Content type
The job of the ContentTypeFilter
is to initialize info.magnolia.cms.core.AggregationState.
It’s created and populated with:
-
Character encoding
-
Original URI
-
Original URL
-
Extension
-
Query string
The AggregationState
is accessible using MgnlContext.getAggregationState()
.
The Content-Type
header is not set by ContentTypeFilter
anymore. The MIME type was incorrectly set according to the request extension. It is now the responsibility of renderers/servlets to set the correct content type. For instance, info.magnolia.rendering.renderer.FreemarkerRenderer sets the content type.
Content type filter can be configured to match requests to content types. See Restricting responses to configured MIME types.
Cookies detector
info.magnolia.personalization.cookie.CookiesDetectorFilter is a personalization filter that detects request cookies and adds them as traits to the aggregation state.
Date
info.magnolia.personalization.date.system.DateDetectorFilter is a simple date trait filter for personalization that stores the current system time in the TraitCollector
.
Country
info.magnolia.personalization.geoip.CountryDetectorFilter is a GeoIP trait filter that detects the user’s country using the IP address of the request for personalization. It adds the country to the aggregation state as a trait. If a GET parameter Country#REQUEST_PARAMETER
with an IP address is supplied, this address is used to resolve the country, which is stored in the TraitCollector
.
Visitor
info.magnolia.personalization.visitor.VisitorDetectorFilter is a visitor trait filter that detects the type of visitor based on the current user and cookies for Personalization.
visitorCookies
can be configured for returning and registered users.
class: info.magnolia.personalization.visitor.VisitorDetectorFilter
returning:
level: 5
name: VISITOR
value: returning
registered:
name: VISITOR
value: registered
new:
maxAge: 86400
name: NEW_VISITOR
value: new
Additional Properties
Additional properties are applicable to the cookie name nodes, that is, to returning
, registered
and new
in the examples above.
Property | Description |
---|---|
|
optional, default is A security setting that prevents cookies from being read by potentially malicious code. |
|
optional, default is Setting the property to |
Multipart request
info.magnolia.cms.filters.MultipartRequestFilter is a filter that determines if a HttpServletRequest
contains multipart content (for example, files or fields) and, if so, parses it into a request attribute for further processing.
You can configure the maximum number of files and fields allowed per request using the fileCountMax
parameter. The total number of files and fields written in the request must be less than the value of fileCountMax
. By default, the maximum is 100
. However, fileCountMax
doesn’t apply to publication requests because they’re authenticated internally. Each file has a maximum size in bytes, which you can configure using the maxFileSize
parameter. The parameter defaults to 2000000000
(two gigabytes).
π server |
|
π filters |
|
π multipartRequest |
|
⬩ class |
info.magnolia.cms.filters.MultipartRequestFilter |
⬩ fileCountMax |
100 |
⬩ maxFileSize |
2000000000 |
Unicode Normalization
info.magnolia.cms.filters.UnicodeNormalizationFilter normalizes the current URI to the NFC form that is used internally.
Registration
info.magnolia.enterprise.registration.RegistrationFilter checks the validity of the registration of a DX Core installation and delegates to the registration form so that the user can enter the license key. The license is also checked in other parts of the code.
If you need to remove the X-Magnolia-Registration header added by this filter, do it at the level of a proxy, load balancer, or CDN.
|
Login
info.magnolia.cms.security.auth.login.LoginFilter handles incoming login requests and delegates to login handlers. The handlers are configured under this filter.
The Login filter verifies that user credentials are authenticated so that only authenticated users can be made into active users. Magnolia uses JAAS for authentication. For more information, see Security.
Redirecting via the To whitelist URLs, add the |
GZip
To improve site performance, info.magnolia.module.cache.filter.GZipFilter replaces text type responses with the gzipped response. This filter passes a ResponseWrapper
instead of the response object it got in the doFilter(..)
call to the filter chain. After all the following filters have been executed, content is extracted from the ResponseWrapper
, gzipped and written to the original response.
Channel
info.magnolia.cms.filters.MultiChannelFilter resolves the channel to use by considering variations of the set channel. The resulting site gets set in info.magnolia.module.site.ExtendedAggregationState.
Multisite
info.magnolia.multisite.filters.MultiSiteFilter is a DX Core filter. It detects which site definition should be used. The filter makes site-related properties available in info.magnolia.cms.core.AggregationState.
Trusted proxy headers
info.magnolia.module.site.filters.TrustedProxyHeadersFilter is a CE and DX Core servlet filter used to enforce security policies on HTTP requests based on headers commonly used by proxies.
server:
filters:
...
trustedProxyHeaders:
class: info.magnolia.module.site.filters.TrustedProxyHeadersFilter
jcr:primaryType: mgnl:content
enabled: true (1)
...
1 | Default filter setting is false . It disables the filter, no header checking is done. |
Configuration
The filter allows you to configure permitted header values and can enforce these policies based on whether forwarding through a proxy is enabled or disabled.
-
If enabled, it checks whether the incoming request headers match the allowed values. If a header does not match the allowed values, the request is blocked.
-
If disabled, the presence of any configured headers in the request will cause the request to be blocked since their presence is unexpected.
TrustedProxyHeadersFilter
reads configuration from a site configuration.
Each site can have a specific configuration.
For configuration details, see the trustedProxyConfig
node description in Configuring a site definition.
Site merge
info.magnolia.module.site.filters.SiteMergeFilter merges channel variations with the site definition. Configurations under this filter override configuration done in the site definition. The filter sets the site definition in the aggregation state.
In the Community Edition, this filter sets the site in the aggregation state. In DX Core, the multisite filter can also set the site.
Logout
info.magnolia.cms.security.LogoutFilter checks to see if the logout attribute mgnlLogout
is set as a request parameter. If this flag is found, the user is logged out and the filter chain restarts with the first filter.
Security callback
info.magnolia.cms.security.SecurityCallbackFilter handles 401 and 403 HTTP response codes and AccessDeniedExceptions
. The filter renders an appropriate login form
that can consist of a redirect or anything else.
Multiple HttpClientCallbacks
with different configuration and behavior can be configured for this filter.
Here is the client callback configuration for the Travel Demo members area redirect and login form.
class: info.magnolia.cms.security.SecurityCallbackFilter
clientCallbacks:
travel-demo-pur:
class: info.magnolia.cms.security.auth.callback.RedirectClientCallback
location: /travel/members/login.html
originalUrlPattern:
class: info.magnolia.cms.util.SimpleUrlPattern
patternString: (*|travel)/members/(profile-update|protected)*
form:
class: info.magnolia.cms.security.auth.callback.FormClientCallback
loginForm: /defaultMagnoliaLoginForm/login.html
Both callback classes implement the info.magnolia.cms.security.auth.callback.HttpClientCallback interface and support their own configuration properties. A custom callback should implement this interface. |
-
info.magnolia.cms.security.auth.callback.FormClientCallback renders a login form using FreeMarker and the template configured with
loginForm
. -
info.magnolia.cms.security.auth.callback.RedirectClientCallback redirects to a configured path or URL. This is useful, for example, in a single sign-on (SSO) context where the login screen is handled by a different application, or to hide the login form from a public instance using a fronting server configuration.
-
info.magnolia.cms.security.auth.callback.AbstractHttpClientCallback provides a number of filtering capabilities:
-
url
. Current request URL decoded and without the context path. -
urlPattern
-
originalUrl
. Original request URL decoded and without the context path, but not modified by any filter. -
originalUrlPattern
-
hostPattern
-
voters
For example, in a multisite installation for the request
http://demo.magnolia-cms.com/travel/about.html
: -
url
is/about.html
-
originalUrl
is/travel/about.html
The Multisite filter removes the first-level node name from the URL.
The methods provided by AbstractHttpClientCallback
are also provided by the info.magnolia.cms.util.UrlPatternDelegate utility class.
-
CSRF security
CsrfSecurityFilter
info.magnolia.cms.security.CsrfSecurityFilter checks the HTTP HTTP_referer header to ensure that the request is not a cross-site request forgery attack. When a possible CSRF attack is detected, the browser returns a 400 Bad Request error and Magnolia logs a security warning to the audit log.
CsrfSecurityFilter
causes a request to fail if:
-
The referer header is empty.
Host: mysite.com/.magnolia/pages/adminCentral.html Referer:
-
The host part of the referer header does not match the requested host.
Host: mysite.com/.magnolia/pages/adminCentral.html Referer: hackersite.io
If you access Magnolia with a script, set the referer header in your script to ensure the script can access Magnolia. Similarly, if you embed Magnolia content into a different website, disable CsrfSecurityFilter or add a voter that bypasses the CSRF filter for any requests coming from the trusted URL.
|
Bypassing CsrfSecurityFilter
You can bypass the CSRF security filter using a voter. By default, info.magnolia.cms.security.CsrfSecurityFilter is bypassed if:
-
The requested URL does not start with
/.magnolia
. Only AdminCentral URLs are vulnerable to CSRF attacks; other URLs are not checked. -
The user is not authenticated for AdminCentral access. Only authenticated requests are vulnerable to CSRF attacks.
-
The request does not have query parameters.
-
The requested resource is somewhere in AdminCentral. Vaadin has its own CSRF protection, so Magnolia hands the responsibility over to Vaadin.
You can create your own whitelist of referer domains or URIs using a voter. The filter is bypassed for the whitelisted referers. In the following example, the filter is bypassed for any requests referred by http://www.example.com
.
class: info.magnolia.cms.security.CsrfSecurityFilter
bypasses:
whitelist:
class: info.magnolia.voting.voters.RequestHeaderPatternSimpleVoter
headerName: referer
pattern: http://wwww.example.com
Property | Description |
---|---|
|
required Voter node. Name the node, for example, |
|
required Fully qualified voter class name. Available classes:
|
|
required Header you want to check (for example, |
|
required Domain or URL pattern that complies with info.magnolia.cms.util.SimpleUrlPattern. The pattern must be present in the header for the filter to be bypassed. |
CsrfSecurityFilter
and Internet Explorer
Some builds of Internet Explorer don’t send the HTTP referer header when submitting a form or when opening a popup. If the referer is not in the HTTP header, CsrfSecurityFilter#handlePossibleCsrf
interprets the request as a potential CSRF attack, which forces the user to log in on the popup. To overcome this issue, add info.magnolia.voting.voters.UserAgentVoter as a voter class to bypass CsrfSecurityFilter
for Internet Explorer.
bypasses:
userAgent:
class: info.magnolia.voting.voters.UserAgentVoter
allowed:
IE11: .*Trident/7.0; rv:11.0.*
Under the allowed
node, you can add a list of regular expressions to match the userAgent
HTTP header. In the example above, Internet Explorer 11 is bypassed.
To ensure the filter is bypassed, make sure to have at least one property under the allowed
node with a value that matches the userAgent
of the browser for which you want to bypass the filter.
For Internet Explorer 11, userAgent
might be Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko
.
Always test changes on a test environment before applying them to a production system. If you add an erroneous regular expression, you will not be able to access AdminCentral anymore. In that case, you will have to use the Groovy Rescue app. |
CsrfCookieTokenFilter
and CsrfSessionTokenFilter
With Magnolia 6.2.14
, info.magnolia.cms.security.CsrfCookieTokenFilter and info.magnolia.cms.security.CsrfSessionTokenFilter replaced the deprecated info.magnolia.cms.security.CsrfTokenSecurityFilter. These two classes cover the functionality below.
Splitting the functionality across two classes simplifies implementation, allowing bypasses to be configured more specifically. Both filters define a CSRF token strategy that exposes methods for creating, validating and renewing tokens. The default strategy is info.magnolia.cms.security.HmacCsrfToken. |
-
CsrfSessionTokenFilter
implements a stateful technique called Synchronizer Token Pattern to prevent CSRF attacks on authenticated users. -
CsrfCookieTokenFilter
implements a stateless technique called Double Submit Cookie to prevent login CSRF attacks.
From Magnolia 6.2.23
, you can also set the secure
and httpOnly
attributes on the CSRF cookie.
Set these through AdminCentral at /server/filters/csrfTokenSecurity/csrfLogin
.
Attribute definitions
Property | Description |
---|---|
|
optional, default is A security setting that prevents cookies from being read by potentially malicious code. |
|
optional, default is Setting the property to |
Bypassing CsrfCookieTokenFilter
and CsrfSessionTokenFilter
You can bypass the CSRF security filter via a voter. By default, both info.magnolia.cms.security.CsrfCookieTokenFilter and info.magnolia.cms.security.CsrfSessionTokenFilter are bypassed if:
-
In REST, the URL starts with
/.rest
. -
In Activation, the URL starts with
/.magnolia/activation
. -
In Vaadin heartbeat, the URL starts with
/.magnolia/admincentral/HEARTBEAT
. -
In Vaadin, the URL starts with
/.magnolia/admincentral/UIDL
. -
In Vaadin on Magnolia 5 AdminCentral, the URL starts with
/.magnolia/admincentral-m5/UIDL
. -
In DAM, the URL starts with
/.dam
. -
In Imaging, the URL starts with
/.imaging
. -
In Resources, the URL starts with
/.resources
. -
In GraphQL, the URL starts with
/.graphql
.
In addition, CsrfSessionTokenFilter
is bypassed by default if in AdminCentral, the URL starts with /.magnolia/admincentral
.
Cross-site security
info.magnolia.multisite.filters.CrossSiteSecurityFilter grants or denies permission to a site when the site is requested through a particular domain name. For example, if you only grant access to the travel
site through www.mgnltravel.com
, no other URL can be used to access the content. When a user tries to access one
site’s content through another site’s domain name, the system displays a HTTP 404 error (page not found). See Cross-site security
URI security
info.magnolia.cms.security.URISecurityFilter checks to see if the active user has permission to access the requested URI. In DX Core, the info.magnolia.multisite.filters.SiteUriSecurityFilter of the Multisite module extends UriSecurityFilter
to provide site-aware functionality.
The following constraints are considered in finding the permissions of the user:
-
URI ACLs of the user’s roles
-
URI ACLs of the user’s groups' roles
-
Permissions on IP addresses
If the user doesn’t have permission to access the URI, JAAS provides a login form. This default behavior of the URI security filter can be changed in the JAAS configuration.
You can configure a custom login form in the URI security filter to replace the default Magnolia login form. The form is configured in /server/filters/securityCallback/clientCallbacks
.
Node name | Value |
---|---|
βΈ¬ form |
|
⬩ class |
info.magnolia.cms.security.auth.callback.FormClientCallback |
⬩ loginForm |
/defaultMagnoliaLoginForm/login.html |
If you don’t grant permission to the custom login form path, a standard Magnolia login form is displayed, usually on the author instance. |
Range
info.magnolia.cms.filters.RangeSupportFilter adds support for ranged requests. Ranged requests are used by iPhone and some other clients to stream videos. In contrast to Android phones, iPhone doesn’t support any other method of streaming videos.
i18n content support
info.magnolia.cms.i18n.I18nContentSupportFilter detects the requested locale and sets the locale in the aggregation state. The filter rewrites the internal current URI, whether virtual or not. It doesn’t rewrite the URI displayed to the user, however. For more information, see Language.
Cache
info.magnolia.module.cache.filter.CacheFilter manages the Magnolia cache.
The cache filter checks if a requested resource is already stored in the cache to avoid recreation of the resource. If the resource is in the cache, then it’s written to the response and the filter chain stops. If the resource is not found in the cache, then a ResponseWrapper
, which not only writes to the standard
response but also saves the response, is passed to the chain. After the filters that follow have been executed (and the requested resource created), the content is extracted from the response wrapper and stored in the cache.
The cache filter is part of Cache core and the respective configuration is in the module configuration.
CORS
info.magnolia.cors.SelfConfiguredCorsFilter and info.magnolia.module.site.filters.SiteAwareCorsFilter (Magnolia 6.2.4+) handle simple and pre-flight requests for cross-origin resource sharing (CORS). For more details, see the CORS page.
Virtual URI
info.magnolia.virtualuri.VirtualUriFilter checks if the requested URI matches a configured URI pattern and executes the URI mapping.
Servlets filter chain
The servlets configured in modules are installed in Magnolia’s servlets filter chain using info.magnolia.cms.filters.ServletDispatchingFilter as the implementing filter class. If the servlet mapping matches the URI, then the service(..)
method of the servlet is called. See Registering a servlet for more.
CMS filter chain
Finally, we arrive at the filter chain which does the page rendering and delivery. The filters are grouped in this filter chain so they share a co-bypass definition.
Repository mapping
info.magnolia.cms.filters.RepositoryMappingFilter handles access to different workspaces. By default, Magnolia is connected with the website
workspace. Therefore a request URI is interpreted as the path to a node in the website
workspace. If you want to address nodes in other workspaces you need to specify a repository mapping in /server/URI2RepositoryMapping
.
Content security
While the URI security filter checks permissions on the URI, info.magnolia.cms.security.ContentSecurityFilter checks if the current user has permission to access the requested content resource. The following constraints are considered in finding the permissions of the user:
-
Workspace-specific ACLs of the user’s roles
-
Workspace-specific ACLs of the user group’s roles
If the user doesn’t have permission for the resource, then JAAS provides a login form. This default behavior of the content security filter can be changed in JAAS configuration.
Aggregator
info.magnolia.cms.filters.AggregatorFilter analyzes the request and stores the results in info.magnolia.cms.core.AggregationState. After this filter, every value the aggregation state can have is known.
Target | Information collected |
---|---|
Page |
* Content node of the requested page * Template |
NodeData |
* |
Variant resolver
info.magnolia.personalization.filter.VariantResolverFilter is a personalization filter that wraps variant nodes. The filter tries to resolve a variant from the current node (from AggregationState
) using all available traits stored in the TraitCollector
and wraps it accordingly, if required. It only uses PersonalizationNodeWrapper
if a variant is resolved. Non-variants are not wrapped.
wrapOnlyPersonalizedNodes: true
Property | Description |
---|---|
|
optional, default is If set to |
Model execution
info.magnolia.rendering.model.ModelExecutionFilter executes the component model before template rendering. The filter looks for a request parameter containing the UUID of the component to execute. The model can send output in which case page rendering is skipped, or return a URI prefixed by redirect
, permanent
or forward
.
Rendering
Finally, info.magnolia.rendering.engine.RenderingFilter is responsible for delivering the requested resource. If the requested resource is data, such as a file, then the data is just copied to the response.
The rendering filter is terminal, meaning it ends the filter chain and filtering process. If no filter before it has been able to fulfill the request and the rendering filter cannot find the page either, then a 404 page not found error is returned. This is the default behavior.
You can change the behavior by adding a terminateChain
property under the rendering filter and setting it to false
. When a request for a page such as /home/some/page
is received and no such page exists in the JCR, your own servlets can have a go at fulfilling the request. The default value for the terminateChain
property is true.
Restricting access to resources
Access to resources is defined in the /modules/resources/config/resourceFilter
filter. By default, the filter allows access to resources as follows:
-
byType
-
css, map, js, htm(l), ico, woff(2), ttf, svg, gif, jp(e)g, tiff, bmp
-
-
byLocation
-
when located in the
webresources
directory.
-
Adding HTTP headers
You can add and configure any header in the /server/filters
folder in the Configuration
app. The info.magnolia.cms.filters.AddHeadersFilter implementation class allows configuration of a filter for adding HTTP headers to enable, for example, CORS. The parameters configured in this filter are added to the HTTP header if the filter is triggered. You can restrict the filter’s scope by adding and configuring a bypasses
node to it. For details, see the Magnolia main filter page.
Example configuration for CORS
Since Magnolia 6.2.4, you can use the cors filter to handle CORS requests.
|
The example allows CORS with header types X-Requested-With
, Content-Type
, Accept
, with the GET
method, and from any origin:
π server |
|
π filters |
|
π HeaderFilterOne |
|
⬩ class |
info.magnolia.cms.filters.AddHeadersFilter |
⬩ enabled |
true |
π headers |
|
⬩ Access-Control-Allow-Headers |
X-Requested-With, Content-Type, Accept |
⬩ Access-Control-Allow-Methods |
GET |
⬩ Access-Control-Allow-Origin |
* |
The position of a filter within the filter chain matters. The appropriate position depends on the use case.
When using this filter to enable cross-origin resource sharing (CORS) - place it after uriSecurity filter.
|
Properties used in the example:
Property | Description |
---|---|
|
required, default is Enables or disables the filter. |
|
required Class that implements info.magnolia.cms.filters.AddHeadersFilter. |
|
optional Headers allowed for the request. |
|
optional The HTTP verbs that are allowed to make the request. |
|
optional The origin of the request (URL/host). The wildcard |
HTTP headers and security best practices
In this subsection, we provide some ideas how you can improve security through select HTTP headers.
Content Security Policy (CSP) header
Content Security Policy governs what a web browser (or a user agent, in general) is allowed to load as part of a page. Setting a CSP header allows the creator of a page to control what other resources might be loaded by the underlying HTML or JavaScript code. This is a powerful way to mitigate many Cross-site scripting (XSS) attacks.
You should list β as part of the header value β the origin and all the endpoints required for the page to function. However, if you allow any endpoint that is not within your control, you are opening a hole through which an attack might be staged. Therefore, be extra careful here.
If necessary, we recommend you customize the header to define your own whitelist.
-
Create a new filter manually in the Configuration app and add the
Content-Security-Policy
property under it. -
An example configuration could look similar to the one below. The path
server/filters/HeaderFilterOne
is only a suggestion. When adding CSP headers, you only need to place the header values into theContent-Security-Policy
property.π server
π filters
π HeaderFilterOne
⬩ class
info.magnolia.cms.filters.AddHeadersFilter
⬩ enabled
true
π headers
⬩ Content-Security-Policy
default-src `self' `unsafe-inline' `unsafe-eval' https://ga-dev-tools.appspot.com https://apis.google.com https://www.google.com https://content.googleapis.com https://ajax.googleapis.com ; img-src `self' data:;
The Vaadin framework performs the CSP check explicitly instead of relying on browser to do so as part of policy execution. You can see official Vaadin statement here. |
See also:
Strict-Transport-Security
(STS) header
The STS header informs the browser that a page should only be accessed over the HTTPS protocol. The browser will use this knowledge and set all future requests for the same domain to go through HTTPS automatically, thus preventing the extra round trip that might be required otherwise.
Using HTTPS instead of HTTP enables traffic encryption between the page and the client, preventing anyone from intercepting the communication. Using this header is considered more secure than using the 301 redirect on the server when an attempt for the over-the-HTTP access is made.
See also:
X-Content-Type-Options
(XCTO) header
XCTO is a marker header that tells the client that the media types (MIME types) advertized as part of the Content-Type headers should be strictly followed and not changed. This helps avoid MIME Type Sniffing.
See also:
X-Frame-Options
(XFO) header
Setting the XFO header tells the browser that the given page is not allowed to be embedded in another page. This header setting helps mitigate stealing content, clickjacking (UI redress attack) or allowing malicious sites to pose as the regular ones and fool the users to not check the URLs closely but think instead that they are on a safe page when they are actually not.
See also:
Custom filters
If you need a custom filter, see Custom filters.