Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-origin CORS support #416

Merged
merged 13 commits into from
Aug 8, 2023
61 changes: 61 additions & 0 deletions dispatcher/src/conf.d/available_vhosts/wknd.vhost
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,67 @@ Include conf.d/variables/custom.vars
# Add header breadcrumbs for help in troubleshooting
<IfModule mod_headers.c>
Header add X-Vhost "publish"

<IfDefine ENABLE_CORS>
################## Start of CORS configuration ##################
SetEnvIfExpr "req_novary('Origin') == ''" CORSType=none CORSProcessing=false
SetEnvIfExpr "req_novary('Origin') != ''" CORSType=cors CORSProcessing=true CORSTrusted=false

SetEnvIfExpr "req_novary('Access-Control-Request-Method') == '' && %{REQUEST_METHOD} == 'OPTIONS' && req_novary('Origin') != ''" CORSType=invalidpreflight CORSProcessing=false
SetEnvIfExpr "req_novary('Access-Control-Request-Method') != '' && %{REQUEST_METHOD} == 'OPTIONS' && req_novary('Origin') != ''" CORSType=preflight CORSProcessing=true CORSTrusted=false
SetEnvIfExpr "req_novary('Origin') -strcmatch '%{REQUEST_SCHEME}://%{HTTP_HOST}*'" CORSType=samedomain CORSProcessing=false

# For requests that require CORS processing, check if the Origin can be trusted
SetEnvIfExpr "%{HTTP_HOST} =~ /(.*)/ " ParsedHost=$1

################## Adapt regex to match CORS origin(s) for applications

################## The following provide access from common developer platforms, to accelerate AEM Headless access to WKND content.
# Developer Localhost
SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(http://localhost(:\d+)?$)#" CORSTrusted=true
# Adobe AppBuilder
SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://experience\.adobe\.com$)#" CORSTrusted=true
# Developer Vercel app
SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*\.vercel\.app$)#" CORSTrusted=true
# Developer Github.io app
SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*\.github\.io$)#" CORSTrusted=true
# Developer Codesandbox.io app
SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://codesandbox\.io$)#" CORSTrusted=true
# Developer CodePen.io app
SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://cdpn\.io$)#" CORSTrusted=true

# Extract the Origin header
SetEnvIfNoCase ^Origin$ ^(.*)$ CORSTrustedOrigin=$1

# Flush If already set
Header unset Access-Control-Allow-Origin
Header unset Access-Control-Allow-Credentials

# Trusted
Header always set Access-Control-Allow-Credentials "true" "expr=reqenv('CORSTrusted') == 'true'"
Header always set Access-Control-Allow-Origin "%{CORSTrustedOrigin}e" "expr=reqenv('CORSTrusted') == 'true'"
Header always set Access-Control-Allow-Methods "GET" "expr=reqenv('CORSTrusted') == 'true'"
Header always set Access-Control-Max-Age 1800 "expr=reqenv('CORSTrusted') == 'true'"
Header always set Access-Control-Allow-Headers "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers" "expr=reqenv('CORSTrusted') == 'true'"

# Non-CORS or Not Trusted
Header unset Access-Control-Allow-Credentials "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'"
Header unset Access-Control-Allow-Origin "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'"
Header unset Access-Control-Allow-Methods "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'"
Header unset Access-Control-Max-Age "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'"

# Always vary on origin, even if its not there.
Header merge Vary Origin

# CORS - send 204 for CORS requests which are not trusted
RewriteCond expr "reqenv('CORSProcessing') == 'true' && reqenv('CORSTrusted') == 'false'"
RewriteRule "^(.*)" - [R=204,L]

# Remove Origin before sending to AEM Publish
RequestHeader unset Origin

################## End of CORS configuration ##################
</IfDefine>
</IfModule>
<Directory />
<IfModule disp_apache2.c>
Expand Down
12 changes: 12 additions & 0 deletions dispatcher/src/conf.d/variables/global.vars
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,15 @@
# and you can fully customize the caching behavior.
#
Define DISABLE_DEFAULT_CACHING

# Enable CORS handling in the dispatcher
#
# By default, CORS is handled by the AEM publish server.
# If you uncomment and define the ENABLE_CORS variable, then CORS will be handled in the dispatcher.
# See the default.vhost file for a suggested dispatcher configuration. Note that:
# a. You will need to adapt the regex from default.vhost to match your CORS domains
# b. Remove the "Origin" header (if it exists) from the clientheaders.any file
# c. If you have any CORS domains configured in your AEM publish server origin, you have to move those to the dispatcher
# (i.e. accordingly update regex in default.vhost to match those domains)
#
Define ENABLE_CORS
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,4 @@
# Allowing CORS headers to be passed through to the publish tier to support headless and SPA Editor use cases.
# https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_request_headers

"Origin"
"Access-Control-Request-Method"
"Access-Control-Request-Headers"

$include "./default_clientheaders.any"
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
// Configuration created by Apache Sling JCR Installer
{
"supportscredentials":true,
"exposedheaders":[
""
],
"supportedmethods":[
"GET",
"HEAD",
"POST"
],
"alloworigin":[
""
],
"maxage:Integer":1800,
"alloworiginregexp":[
"http://localhost:.*"
],
"allowedpaths":[
"/content/_cq_graphql/wknd-shared/endpoint.json",
"/graphql/execute.json.*"
],
"supportedheaders":[
"Origin",
"Accept",
"X-Requested-With",
"Content-Type",
"Access-Control-Request-Method",
"Access-Control-Request-Headers",
"authorization"
]
"alloworigin":[
""
],
"alloworiginregexp":[
"http://localhost:.*"
],
"allowedpaths": [
"/graphql/execute.json.*",
"/content/_cq_graphql/wknd-shared/endpoint.json",
"/content/experience-fragments/.*"
],
"supportedheaders": [
"Origin",
"Accept",
"X-Requested-With",
"Content-Type",
"Access-Control-Request-Method",
"Access-Control-Request-Headers",
"Authorization"
],
"supportedmethods":[
"GET",
"HEAD",
"POST"
],
"maxage:Integer": 1800,
"supportscredentials": true,
"exposedheaders":[ "" ]
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
// Configuration created by Apache Sling JCR Installer
// This OSGi configuration is to support local development on the AEM SDK.
// The Dispatcher CORS configuration should be used when deploying to AEM as a Cloud Service.
// See https://experienceleague.adobe.com/docs/experience-manager-learn/getting-started-with-aem-headless/deployments/configurations/cors.html
{
"supportscredentials":false,
"exposedheaders":[
""
],
"supportedmethods":[
"GET",
"HEAD",
"POST"
],
"alloworigin":[
""
],
"maxage:Integer":1800,
"alloworiginregexp":[
"http://localhost:.*"
],
"allowedpaths":[
"/content/_cq_graphql/wknd-shared/endpoint.json",
"/graphql/execute.json.*"
],
"supportedheaders":[
"Origin",
"Accept",
"X-Requested-With",
"Content-Type",
"Access-Control-Request-Method",
"Access-Control-Request-Headers"
]
"alloworigin":[
""
],
"alloworiginregexp":[
"http://localhost:.*"
],
"allowedpaths": [
"/graphql/execute.json.*",
"/content/_cq_graphql/wknd-shared/endpoint.json",
"/content/experience-fragments/.*"
],
"supportedheaders": [
"Origin",
"Accept",
"X-Requested-With",
"Content-Type",
"Access-Control-Request-Method",
"Access-Control-Request-Headers"
],
"supportedmethods":[
"GET",
"HEAD",
"POST"
],
"maxage:Integer": 1800,
"supportscredentials": false,
"exposedheaders":[ "" ]
}
Loading