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 do not themselves create responses, but instead provide universal functions that can be "attached" to any type of servlet or JSP page.

Since the filter chain is responsible for request handling in Magnolia, the default chain illustrates how filters are used to process requests. This document provides minimal information on filters. For more, 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

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") Voter
to a filter with an erroneous regular expression, you won't be able to access admincentral anymore. (In such case you have to use Groovy Rescue App).

Context

The first filter in the filter chain is 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ContextFilter
. This filter initializes MgnlContext and configures MDC loggingMgnlContext is local to the request and available on every further filter. The context provides a lot of useful functions, see 
$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") MgnlContext
 for details.

Content type

The job of the ContentTypeFilter is to initialize the non-content related attributes of the 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") AggregationState
.

It's created and populated with:

  • Character encoding
  • Original URI
  • Original URL
  • Extension
  • Query string

The AggregationState is accessible using MgnlContext.getAggregationState().

   (warning) Magnolia 5.4.5+ 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 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") FreemarkerRenderer
 and 
$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") JspRenderer
 set the content type. 

  (warning) Magnolia 5.4.3+ Content type filter can be configured to match requests to content types. See Restricting responses to configured MIME types.

Cookies detector

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") CookiesDetectorFilter
 is a personalization filter that detects request cookies and adds them as traits to the aggregation state.

Date

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") DateDetectorFilter
 is a simple date  trait  filter for  personalization  that stores current system time in the  TraitCollector .

Country

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") VisitorDetectorFilter
 is a visitor trait filter that detects the type of visitor based on the current user and cookies for personalizationvisitorCookies can be configured for returning and registered users.

Node name

Value

 
visitor


 
visitorCookies


 
returning

returning

 
level

5

 
name

VISITOR

 
value

returning

 
registered

registered

 
name

VISITOR

 
value

registered

 
new

new

 
maxAge

86400

 
name

NEW_VISITOR

 
value

new

 
class

info.magnolia.personalization.visitor.VisitorDetectorFilter

Additional Properties

(Applicable to the cookie name nodes, i.e. to "returning", "registered" and "new" in the above examples.)

httpOnly

optional, default is true

A security setting that prevents cookies from being read by a potentially malicious code.

secure

optional, default is false  

Setting the property to true (recommended) will prevent cookies from being sent if the protocol used is insecure (HTTP instead of HTTPS).

Device detection

Only used by the STK.

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") DeviceDetectionFilter
 detects the type of device requesting content. Device detection is done using the Mobile Detect API.

Multipart request

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") CosMultipartRequestFilter
 checks to see if there are any binary uploads such as form attachments in the request, extracts the binaries and persists them in the JCR.

Unicode Normalization

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") UnicodeNormalizationFilter
 normalizes the current URI to the NFC form that is used internally.

Registration

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") RegistrationFilter
 checks the validity of the registration of an enterprise 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 such as in the STK.

Login

Handles incoming login requests and delegates to login handlers. The handlers are configured under this filter. 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") LoginFilter
 checks to verify that user credentials have been authenticated so that only authenticated users can be made active users. Magnolia uses JAAS for authentication. For more information see Security.

Activation

The activation filter handles incoming activation requests. This filter is the receiving part of the activation process.

The activation filter is implemented using 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ReceiveFilter
 from the Activation module. In the Enterprise Edition, 
$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") RegistrationFilter
 (included in the  Transactional Activation module) extends ReceiveFilter to provide transaction related communications with syndicators.

Here's an example of how to use the bypass feature to avoid specific filters. This configuration will only handle requests where the URI starts with /.magnolia/activation.

Node name

Value

 
activation


 
bypasses


 
allButActivationHandler


 
class

info.magnolia.voting.voters.URIStartsWithVoter

 
not

true

 
pattern

/.magnolia/activation

 
class

info.magnolia.module.exchangetransactional.XAReceiveFilter

GZip

To increase the performance of the site 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") GZipFilter
 replaces text type responses with the gzipped response. The trick in this filter is that it 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

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") MultiChannelFilter
 resolves the channel to use by considering variations of the set channel. Resulting site gets set in 
$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ExtendedAggregationState
.

Multisite

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") MultiSiteFilter
 is an Enterprise Edition Pro filter. It detects which site definition should be used. The filter makes site related properties available in the 
$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") AggregationState
.

Site merge

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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 the Enterprise Edition, the multisite filter can also set the site.

Logout

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") LogoutFilter
 checks to see if the logout attribute mgnlLogout is set as a request parameter. If this flag is found, the user will be logged out and the filter chain will restart with the first filter.

Security callback

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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.

Node name

Value

 
securityCallback


 
clientCallbacks


 
travel-demo-pur


 
originalUrlPattern


 
class

info.magnolia.cms.util.SimpleUrlPattern

 
patternString

(*|travel)/members/(profile-update|protected)*

 
class

info.magnolia.cms.security.auth.callback.RedirectClientCallback

 
location

/travel/members/login.html

 
form


 
class

info.magnolia.cms.security.SecurityCallbackFilter

(warning) Both callback classes implement the 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") HttpClientCallback
 interface and support their own configuration properties. A custom callback should implement this interface.

 Classes:

  • $webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") RedirectClientCallback
     redirects to a configured path or URL. This is useful, for example in 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.
  • $webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") FormClientCallback
     renders a login form using Freemarker and the template configured with loginForm.

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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 utility class

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") UrlPatternDelegate
.

CSRF security

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") CsrfSecurityFilter
 checks the HTTP referer header to ensure that the request is not a cross-site request forgery attack. When a possible CSRF attack is detected the system serves a 400 Bad Request status to the browser. Magnolia also logs a security warning to the audit log.

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 the CSRF filter or add a voter (see below) that bypasses the CSRF filter for any requests coming from the trusted URL.

The CSRF security filter 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

Bypassing the filter

You can bypass the CSRF security filter with a voter.

By default, the filter 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 referrer domains or URIs using a voter. The filter is bypassed for the whitelisted referrers. In this example we bypass the filter for any requests referred by   http://www.trustedsite.com/  .

Node nameValue

 
csrfSecurity


 
bypasses


 
BypassWhenNotInAdminCentral


 
BypassWhenNotAuthenticated


 
BypassWhenNoQueryParameters


 
BypassWhenVaadinRequest


 
whitelist


 
class

info.magnolia.voting.voters.RequestHeaderPatternSimpleVoter

 
headerName

referer

 
pattern

http://www.trustedsite.com

 
class

info.magnolia.cms.security.CsrfSecurityFilter

Voter properties:

<voter node>

required

Voter node. Name the node for example whitelist.

class

required

 Fully-qualified voter class name.

Available classes:

  • info.magnolia.voting.voters.RequestHeaderPatternSimpleVoter: Checks for a URL pattern compliant to 
    $webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") SimpleUrlPattern
     such as  http://www.trustedsite.*
  • info.magnolia.voting.voters.RequestHeaderPatternRegexVoter: Checks for a regular expression pattern.

headerName

required

Header you are checking such as referer(warning) This is not a misspelling.

pattern

required

Domain or URI pattern compliant to 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") SimpleUrlPattern
. The pattern must be present in the header for the filter to be bypassed. 

CSRF and Internet Explorer 

Some builds of Internet explorer don't send the HTTP request header referrer when submitting a form or when opening a pop up. If the referrer is not in the HTTP request header, CsrfSecurityFilter#handlePossibleCsrf interprets the request as potential CSRF attack which forces the user to login on the pop up. (See  MAGNOLIA-6211 - Getting issue details... STATUS ). To overcome this "issue", add voter class 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") UserAgentVoter
 to bypass CsrfSecurityFilter for Internet Explorer.

Node nameValue

 
csrfSecurity


 
bypasses


 
userAgent


 
allowed


 
IE6

.*MSIE 6\.0.*

 
IE11

.*Trident/7.0; rv:11.0.*

 
class

info.magnolia.voting.voters.UserAgentVoter

Below the node allowed you can add a list of regular expressions to match the HTTP header userAgent. In the example above we have bypassed Internet Explorer 6 and 11.

To ensure the filter is bypassed, make sure to have at least one property on the node allowed with a value which will match the userAgent of the browser for which you want to bypass the filter. (For Internet Explorer 11, the userAgent might be Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko.)

(warning) Always test changes on test environment before applying it to a productive system. When adding an erroneous regular expression - you won't access admin central anymore. (In such case you have to use Groovy Rescue App).

Cross site security

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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.travel.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

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") URISecurityFilter
 checks to see if the active user has permission to access the requested URI. In the Enterprise Edition, 
$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") SiteUriSecurityFilter
 (included in 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 does not have the permission to access the URI then JAAS will provide a login form. This default behavior of the URI security filter can be changed in JAAS configuration.

You can configure your own login form in the URI security filter to replace the default Magnolia login form. The form is configured in /server/filters/securityCallback/clientCallbacks. Here is an example of a custom form used to grant public users access to a restricted members area. Authentication is delegated to the custom form when a particular URI is accessed.

If you don't grant permission to the custom login form path then a standard Magnolia login form will be displayed, usually on author instance.

Range

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") RangeSupportFilter
 adds support for ranged requests. Ranged requests is used by iPhone and some other clients to stream videos. In contrast to Android phones, iPhone does not support any other method of streaming videos.

i18n content support

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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 does not rewrite the URI displayed to the user, however. See Language.

Cache

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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 will be 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 can be found in the module configuration.

Virtual URI

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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 the 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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

Whereas the URI security filter checks permissions on the URI, 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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's groups' roles

If the user does not have permission to the resource, then JAAS will provide a login form. This default behavior of the content security filter can be changed in JAAS configuration.

Aggregator

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") AggregatorFilter
 analyses the request and stores the results in the 
$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") AggregationState
. After this filter, every value the aggregation state can have is known.

Target

Collected information

Page

  • Content node of the requested page
  • Template

NodeData

  • NodeData object of the requested data
  • Template if a template is connected with the NodeData

Variant resolver

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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 was resolved. Non-variants are not wrapped.

Node nameValue

 
server


 
filters


 
cms


 
variantResolver


 
wrapOnlyPersonalizedNodes

true

Property:

wrapOnlyPersonalizedNodes

optional , default is false

If set to true, only page variants are wrapped.

Intercept

(warning) Deprecated since Magnolia 5.1. This filter is no longer used. It's function is now handled in part by the page editor and in part by the  MultiChannelFilter .

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") InterceptFilter
 handles administrative requests from AdminCentral like

  • Sort nodes
  • Delete a node
  • Switch to preview

Model execution

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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 redirectpermanent or forward.

Rendering

Finally, 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") 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 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

The AddHeadersFilter implementation class allows configuration of a filter for adding HTTP headers to enable, for example, Cross-origin resource sharing (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 please refer to the Magnolia main filter page.

Example configuration for CORS

The example allows CORS with header types X-Requested-With, Content-Type, Accept, with the GET method, and from any origin:

Node nameValue

 
server


 
filters


 
HeaderFilterOne


 
enabled

true

 
class

info.magnolia.cms.filters.AddHeadersFilter

 
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 whithin 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:

PropertyValue
enabled

required, deafult is false

Enables or disables the filter.

class

required

Class that implements the filter: AddHeadersFilter.

Access-Control-Allow-Headers

optional

Headers allowed for the request.

Access-Control-Allow-Methods

optional

The HTTP verbs that are allowed to make the request.

See: RFC 7231, section 4: Request methods and RFC 5789, section 2: Patch method.

Access-Control-Allow-Origin

optional

The origin of the request (URL/host).

The wildcard * is used to allow any origin.

Custom filters

If you need a custom filter, please read Custom filters.

#trackbackRdf ($trackbackUtils.getContentIdentifier($page) $page.title $trackbackUtils.getPingUrl($page))
  • No labels