From 6a30564068802cd3ebb5f2ba4d8a32f0d2663ca7 Mon Sep 17 00:00:00 2001 From: mel Date: Mon, 8 Jun 2026 14:18:37 -0700 Subject: [PATCH 1/2] Add docker configuration for keycloak. --- .gitignore | 3 ++ docker/bootstrap.php | 60 +++++++++++++++++++++++++++++- docker/docker-compose.keycloak.yml | 37 ++++++++++++++++++ docker/etc/environment | 2 + docker/realm.json | 56 ++++++++++++++++++++++++++++ 5 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 docker/docker-compose.keycloak.yml create mode 100644 docker/realm.json diff --git a/.gitignore b/.gitignore index 3a8e3043b2..f290ef555a 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,6 @@ cypress.env.json # OIDC plugin activation flag activate-oidc-plugin + +# Docker cert files for keycloak +docker/certs diff --git a/docker/bootstrap.php b/docker/bootstrap.php index 9c876ccb51..8182a37a05 100644 --- a/docker/bootstrap.php +++ b/docker/bootstrap.php @@ -44,6 +44,8 @@ function get_host_and_port($value, $default_port) 'atom.elasticsearch_host' => getenv_or_fail('ATOM_ELASTICSEARCH_HOST'), 'atom.memcached_host' => getenv_or_fail('ATOM_MEMCACHED_HOST'), 'atom.gearmand_host' => getenv_or_fail('ATOM_GEARMAND_HOST'), + 'atom.keycloak_host' => getenv_default('ATOM_KEYCLOAK_HOST', ''), + 'atom.keycloak_port' => getenv_default('ATOM_KEYCLOAK_PORT', '9000'), 'atom.mysql_dsn' => getenv_or_fail('ATOM_MYSQL_DSN'), 'atom.mysql_username' => getenv_or_fail('ATOM_MYSQL_USERNAME'), 'atom.mysql_password' => getenv_or_fail('ATOM_MYSQL_PASSWORD'), @@ -113,7 +115,7 @@ function get_host_and_port($value, $default_port) read_only: false htmlpurifier_enabled: false csp: - response_header: Content-Security-Policy + response_header: Content-Security-Policy-Report-Only directives: > default-src 'self'; font-src 'self' https://fonts.gstatic.com; @@ -124,8 +126,64 @@ function get_host_and_port($value, $default_port) worker-src 'self' blob:; connect-src 'self' https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com https://*.googleapis.com *.google.com https://*.gstatic.com data: blob:; frame-ancestors 'self'; +EOT; + + if (!empty($CONFIG['atom.keycloak_host'])) { + $keycloakParts = get_host_and_port($CONFIG['atom.keycloak_host'], $CONFIG['atom.keycloak_port']); + $keycloakBaseUrl = 'http://localhost:' . $keycloakParts['port']; + + $app_yml .= << Date: Mon, 8 Jun 2026 14:20:12 -0700 Subject: [PATCH 2/2] Update oidc files to work with keycloak docker. --- plugins/arOidcPlugin/lib/oidcUser.class.php | 17 ++++++++++++++++- .../modules/oidc/actions/loginAction.class.php | 4 ++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/plugins/arOidcPlugin/lib/oidcUser.class.php b/plugins/arOidcPlugin/lib/oidcUser.class.php index 3a6642feb7..14ef04f587 100644 --- a/plugins/arOidcPlugin/lib/oidcUser.class.php +++ b/plugins/arOidcPlugin/lib/oidcUser.class.php @@ -455,7 +455,22 @@ protected function setOidcProviderDetails(string $providerId = ''): bool $this->oidcClient->setProviderUrl($provider['url']); $this->oidcClient->setClientID($provider['client_id']); $this->oidcClient->setClientSecret($provider['client_secret']); - $this->oidcClient->setIssuer($provider['url']); + if (isset($provider['issuer'])) { + $this->oidcClient->setIssuer($provider['issuer']); + + $endpointOverrides = []; + foreach (['authorization_endpoint', 'token_endpoint', 'userinfo_endpoint', 'jwks_uri', 'end_session_endpoint'] as $endpointName) { + if (!empty($provider[$endpointName])) { + $endpointOverrides[$endpointName] = $provider[$endpointName]; + } + } + + if (!empty($endpointOverrides)) { + $this->oidcClient->providerConfigParam($endpointOverrides); + } + } else { + $this->oidcClient->setProviderUrl($provider['url']); + } return true; } diff --git a/plugins/arOidcPlugin/modules/oidc/actions/loginAction.class.php b/plugins/arOidcPlugin/modules/oidc/actions/loginAction.class.php index 3807f627ae..725454f993 100644 --- a/plugins/arOidcPlugin/modules/oidc/actions/loginAction.class.php +++ b/plugins/arOidcPlugin/modules/oidc/actions/loginAction.class.php @@ -34,8 +34,8 @@ public function execute($request) $this->context->user->setAttribute('atom-login-referer', $request->getReferer()); } - if ($request->isMethod('post') || isset($_REQUEST['code'])) { - if (null !== $providerId = $this->context->user->parseProviderIdFromUrl($this->context->user->getAttribute('atom-login-referer', null))) { + if (($request->isMethod('post') || isset($_REQUEST['code'])) && null !== $this->context->user->getAttribute('atom-login-referer')) { + if (null !== $providerId = $this->context->user->parseProviderIdFromUrl($this->context->user->getAttribute('atom-login-referer'))) { $this->context->user->validateProviderId($providerId, true); }