CORS

This page describes how to configure Magnolia properties that handle simple and pre-flight requests for Cross-Origin Resource Sharing (CORS). For more information about CORS itself, see for example the Cross-Origin Resource Sharing (CORS) page at developer.mozilla.org.

Introduction

The implementation for CORS has been available in Magnolia since the 6.2.4 release and is provided by the following filters:

Which filter is to be used is specified in the Magnolia filter chain under /server/filters/cors.

In Magnolia 6.2.3 and below, you can use the AddHeadersFilter. For more details, see Filters: Adding HTTP headers.

Global CORS filter

The SelfConfiguredCorsFilter is a global CORS filter and its properties are configured directly in the server, for example:

server:
  filters:
    cors:
      class: info.magnolia.cors.SelfConfiguredCorsFilter
      uris:
        rest:
          patternString: /.rest/*
      allowedOrigins:
        - https://example.com
        - https://magnolia-cms.com
      allowedMethods:
        - GET
        - OPTIONS
        - POST
      allowedHeaders:
        - '*'

Site-aware CORS filters

In Magnolia DX Core

In a multisite setup, the SiteAwareCorsFilter is usually configured separately for each site under /modules/multisite/config/sites/<site-name>/cors, for example:

modules:
  multisite:
    config:
      sites:
        travel:
          cors:
            travel:
              uris:
                rest:
                  patternString: /.rest/*
              allowedOrigins:
                - '*'
              allowedMethods:
                - GET
              allowedHeaders:
                - Accept
                - Content-Type
                - Origin
                - X-PINGOTHER
                - X-Requested-With

Then, in the server part, make sure that the SiteAwareCorsFilter is configured.

server:
  filters:
    cors:
      class: info.magnolia.module.site.filters.SiteAwareCorsFilter

In Magnolia CE

In Magnolia Community Edition, where only one site can be configured and used, the CORS configuration can be defined under /modules/site/config/<site-name>/cors.

Configuration

Properties

Property Description

<CORS configuration name>

required (site-aware configuration only)

Add a node for each CORS configuration. The name is arbitrary, but it is good practice to use a descriptive name.

     uris <pattern name>

required

List of named URI patterns in the form patternString: <SimpleUrlPattern>. The URIs will be matched against the incoming CORS request.

Example
uris:
  restReadWrite:
    patternString: /.rest/*
  restReadOnly:
    patternString: /.read/*

     allowedOrigins

required

List of allowed origin domains, for example:

allowedOrigins:
  - https://example.com
  - https://magnolia-cms.com

     allowedMethods

required

List of allowed HTTP methods, for example:

allowedMethods:
  - GET
  - POST

     allowedHeaders

required

List of allowed HTTP header fields, for example:

allowedHeaders:
  - Date
  - X-Device-Id

     supportsCredentials

required, default is false

When set to true, the request can be made with credential information.

     maxAge

required, default is -1

Value in seconds to cache pre-flight request results, for example:

maxAge: 600

Examples

In the following examples, the curl command is used to query the /magnolia-travels/Kyoto tour from the Magnolia DX Core Travel Demo. The following configuration is assumed to be in place:

  • The tours_v1 delivery endpoint, configured in /tours/restEndpoints/delivery/tours_v1.yaml:

    /tours/restEndpoints/delivery/tours_v1.yaml
    class: info.magnolia.rest.delivery.jcr.v2.JcrDeliveryEndpointDefinition
    nodeTypes:
      - mgnl:content
    includeSystemProperties: false
    bypassWorkspaceAcls: false
    limit: 50
    workspace: tours
    references:
      - name: tourTypes
        propertyName: tourTypes
        referenceResolver:
          class: info.magnolia.rest.reference.jcr.JcrReferenceResolverDefinition
          targetWorkspace: category
      - name: destinations
        propertyName: destination
        referenceResolver:
          class: info.magnolia.rest.reference.jcr.JcrReferenceResolverDefinition
          targetWorkspace: category
      - name: tourImageReference
        propertyName: image
        referenceResolver:
          class: info.magnolia.rest.reference.dam.AssetReferenceResolverDefinition
          assetRenditions:
            - 960x720
  • The SiteAwareCorsFilter filter configured at /server/filters/cors@class.

  • A CORS configuration for the travel site under /modules/multisite/config/sites/travel/cors/travel:

    /modules/multisite/config/sites/travel/cors/travel
      uris:
        rest:
          patternString: /.rest/*
      allowedOrigins:
        all: *
      allowedMethods:
        all: *
      allowedHeaders:
        accept: Accept
        content-type: Content-Type
        origin: Origin
        x-pingother: X-PINGOTHER
        x-requested-with: X-Requested-With

Notes: To receive responses for the curl command, appropriate security permissions and web access must be configured via the Security app. In the curl command, the options -v -o /dev/null are used to limit the output of the command just to the information contained in the headers.

Simple CORS request

In this example, a simple CORS request is sent. The port number is used to indicate that the origin of the request is different from the server that is queried:

curl -X GET 'http://localhost:8080/magnoliaAuthor/.rest/delivery/tours/v1/magnolia-travels/Kyoto' -H "Origin: http://localhost:8081" -v -o /dev/null -u superuser:superuser

The command sends the following header, where the origin can be seen specified in the Origin header field (line 6):

GET /magnoliaAuthor/.rest/delivery/tours/v1/magnolia-travels/Kyoto HTTP/1.1
Host: localhost:8080
Authorization: Basic c3VwZXJ1c2VyOnN1cGVydXNlcg==
User-Agent: curl/7.58.0
Accept: */\*
Origin: http://localhost:8081

Since the above CORS configuration allows any origin, the server returns the 200 HTTP code in the response header:

HTTP/1.1 200
Set-Cookie: JSESSIONID=A8890F8F3D05C22111D88675691F4B5A; Path=/magnoliaAuthor; HttpOnly; SameSite=Strict
X-Magnolia-Registration: Registered
Pragma: no-cache
Cache-Control: no-cache, no-store, must-revalidate, max-age=0
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Access-Control-Allow-Origin: *
Vary: Accept-Language
Content-Language: en
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 10 Nov 2020 09:28:11 GMT

If you modified the allowedOrigins list to allow, for example, only requests coming from http://localhost:9000, then the server would return the 403 HTTP code in the response, meaning that access to the requested resource is forbidden for some reason:

HTTP/1.1 403
Set-Cookie: JSESSIONID=FB0FA9481A997D85FDB4F486FB10CB91; Path=/magnoliaAuthor; HttpOnly; SameSite=Strict
X-Magnolia-Registration: Registered
Pragma: no-cache
Cache-Control: no-cache, no-store, must-revalidate, max-age=0
Expires: Thu, 01 Jan 1970 00:00:00 GMT
WWW-Authenticate: FormBased
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 10 Nov 2020 13:46:41 GMT

In addition, an entry like this would be logged on the server:

WARN info.magnolia.cors.AbstractCorsFilter : CORS failed due to: Origin [http://localhost:8081] not allowed

Pre-flight CORS request

In a pre-flight CORS request, the client sends a short OPTIONS request to find out whether the server accepts full requests with parameters specified in the header fields of the short pre-flight OPTIONS request.

Both of the two examples that follow utilize the CORS travel configuration mentioned above. The curl commands issue a pre-flight OPTIONS request inquiring whether the endpoint can be queried from http://localhost:8081.

Return code 204 - No Content

However, the first curl command, however, checks whether the GET HTTP method can be used:

curl -X OPTIONS 'http://localhost:8080/magnoliaAuthor/.rest/' -H "Origin: http://localhost:8081" -H "Access-Control-Request-Method: GET" -v -o /dev/null -u superuser:superuser

The header that is sent is:

> OPTIONS /magnoliaAuthor/.rest/ HTTP/1.1
> Host: localhost:8080
> Authorization: Basic c3VwZXJ1c2VyOnN1cGVydXNlcg==
> User-Agent: curl/7.58.0
> Accept: */*
> Origin: http://localhost:8081
> Access-Control-Request-Method: GET
Since the GET method is allowed, the server returns code 204. It successfully processed the request but is not returning any content:
< HTTP/1.1 204
< Set-Cookie: JSESSIONID=282C24905B8E022C9F18A5FC08419C4C; Path=/magnoliaAuthor; HttpOnly; SameSite=Strict
< X-Magnolia-Registration: Registered
< Pragma: no-cache
< Cache-Control: no-cache, no-store, must-revalidate, max-age=0
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Vary: Access-Control-Request-Method,Access-Control-Request-Headers
< Access-Control-Allow-Methods: GET
< Access-Control-Allow-Headers: accept,content-type,origin,x-pingother,x-requested-with
< Access-Control-Allow-Origin: *
< Date: Thu, 12 Nov 2020 07:52:51 GMT

Return code 403 - Forbidden

The second curl command intends to use the POST HTTP method instead:

curl -X OPTIONS 'http://localhost:8080/magnoliaAuthor/.rest/' -H "Origin: http://localhost:8081" -H "Access-Control-Request-Method: POST" -v -o /dev/null -u superuser:superuser

The following header is sent:

> OPTIONS /magnoliaAuthor/.rest/ HTTP/1.1
> Host: localhost:8080
> Authorization: Basic c3VwZXJ1c2VyOnN1cGVydXNlcg==
> User-Agent: curl/7.58.0
> Accept: */*
> Origin: http://localhost:8081
> Access-Control-Request-Method: POST

Since no other method than GET is allowed, the server returns HTTP code 403, meaning it is refusing to give the requested resource in this case:

< HTTP/1.1 403
< Set-Cookie: JSESSIONID=EDB3A94A37E7FC48274F5994D1256019; Path=/magnoliaAuthor; HttpOnly; SameSite=Strict
< X-Magnolia-Registration: Registered
< Pragma: no-cache
< Cache-Control: no-cache, no-store, must-revalidate, max-age=0
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< WWW-Authenticate: FormBased
< Content-Type: text/html;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Thu, 12 Nov 2020 08:03:24 GMT
Related topics
Feedback