OJS 3.2.1.1: multi-domain, multi-journal installation: journals with custom domain not editable from central Administration menu

OJS 3.2.1.1

config.inc.php:

base_url = "https://maindomain.tld"
base_url[index] = https://maindomain.tld/index
base_url[abc] = https://customdomain.tld
base_url[def] = https://maindomain.tld/def
restful_urls = On

Apache configuration, maindomain.tld.conf:

RewriteEngine On
RewriteBase /
RewriteRule ^api/v1(.*)$ /index.php/api/v1$1 [L,R=307]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /index.php/$1 [QSA,L]

Apache configuration, customdomain.tld.conf

Header unset Access-Control-Allow-Origin
Header unset Access-Control-Allow-Headers
Header unset Access-Control-Allow-Methods
Header always set Access-Control-Allow-Origin "*"
Header always  set Access-Control-Allow-Headers "Content-Type, X-Csrf-Token"
Header always  set Access-Control-Allow-Methods "HEAD, POST, GET, OPTIONS, PUT, DELETE"
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_METHOD} !OPTIONS
RewriteRule ^api/v1(.*)$ /index.php/abc/api/v1$1 [L,R=307]
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [L,R=200]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /index.php/abc/$1 [QSA,L]

Steps:

  1. login as admin in maindomain.tld
  2. login as admin in customdomain.tld
  3. go to “Administration” in the left sidebar. This is always hosted from maindomain.tld
  4. go to “Hosted Journals”
  5. click on “Edit” for journal abc (which uses customdomain.tld)
  6. click “Save”
  7. This fires OPTIONS and PUT requests to customdomain.tld
  8. observe HTTP 403 with response body {"error":"form.csrfInvalid","errorMessage":"The form could not be submitted. You may have been logged out. Please reload the page and try again."}

Note that all CORS-headers are correctly sent! There are no complaints about missing or duplicate Access-Control-Allow-Origin headers or the like.

I dived into the OJS code and found this in lib/pkp/classes/security/authorization/internal/ApiCsrfMiddleware.inc.php:

$session = Application::get()->getRequest()->getSession();
return $session && $session->getCSRFToken() === $server['HTTP_X_CSRF_TOKEN'];

And this seems to be the source of the 403. It turns out that the HTTP_X_CSRF_TOKEN which is sent from maindomain.tld is different from the $session->getCSRFToken() which belongs to the login session of customdomain.tld.

This leads me to believe that using the Administration menu (which is always from maindomain.tld) will never work for journals which use a custom domain.

Does this look correct, or am I missing something?

Thanks in advance,
Jan Pieter

Opened this as an issue on Github: OJS 3.2.1.1: multi-domain, multi-journal installation: journals with custom domain not editable from central Administration menu · Issue #7163 · pkp/pkp-lib · GitHub