feat(web-app-joomla): reliable first-run install, safe debug toggler, DB patching, LDAP scaffolding

Why
- Fix flaky first-run installs and make config edits idempotent.
- Prepare LDAP support and allow optional inline CSP for UI.
- Improve observability and guard against broken configuration.php.

What
- config/main.yml: enable features.ldap; add CSP flags (allow inline style/script elem); minor spacing.
- tasks/: split into 01_install (wait for core, absolute CLI path), 02_debug (toggle $debug/$error_reporting safely), 03_patch (patch DB creds in configuration.php), 04_ldap (configure plugin via helper), 05_assert (optional php -l).
- templates/Dockerfile.j2: conditionally install/compile php-ldap (fallback to docker-php-ext-install with libsasl2-dev).
- templates/cli-ldap.php.j2: idempotently enable & configure Authentication - LDAP from env.
- templates/docker-compose.yml.j2: build custom image when LDAP is enabled; mount cli-ldap.php; pull_policy: never.
- templates/env.j2: add site/admin vars, MariaDB connector/env, full LDAP env.
- vars/main.yml: default to MariaDB (mysqli), add JOOMLA_* vars incl. JOOMLA_CONFIG_FILE.

Notes
- LDAP path implemented but NOT yet tested end-to-end.
- Ref: https://chatgpt.com/share/68b068a8-2aa4-800f-8cd1-56383561a9a8.
This commit is contained in:
2025-08-28 16:33:45 +02:00
parent dece6228a4
commit 18f3b1042f
12 changed files with 351 additions and 16 deletions

View File

@@ -0,0 +1,15 @@
FROM {{ JOOMLA_IMAGE }}:{{ JOOMLA_VERSION }}
{% if JOOMLA_LDAP_ENABLED %}
ENV DEBIAN_FRONTEND=noninteractive
RUN set -eux; \
apt-get update; \
PHPV="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')" || PHPV=""; \
apt-get install -y --no-install-recommends "php${PHPV}-ldap" \
|| ( \
apt-get install -y --no-install-recommends libldap2-dev libsasl2-dev pkg-config; \
docker-php-ext-configure ldap --with-ldap=/usr --with-ldap-sasl=/usr \
|| docker-php-ext-configure ldap --with-ldap=/usr; \
docker-php-ext-install -j"$(nproc)" ldap \
); \
rm -rf /var/lib/apt/lists/*
{% endif %}

View File

@@ -0,0 +1,54 @@
<?php
// Tiny Joomla CLI to enable + configure Authentication - LDAP plugin.
// Safe to run multiple times.
define('_JEXEC', 1);
if (PHP_SAPI !== 'cli') { fwrite(STDERR, "CLI only\n"); exit(1); }
$root = __DIR__ . '/..';
require $root . '/includes/defines.php';
require $root . '/includes/framework.php';
$app = \Joomla\CMS\Factory::getApplication('administrator');
$dbo = \Joomla\CMS\Factory::getDbo();
// Locate the LDAP plugin row in #__extensions
$query = $dbo->getQuery(true)
->select('*')
->from($dbo->quoteName('#__extensions'))
->where($dbo->quoteName('type') . ' = ' . $dbo->quote('plugin'))
->where($dbo->quoteName('folder') . ' = ' . $dbo->quote('authentication'))
->where($dbo->quoteName('element') . ' = ' . $dbo->quote('ldap'));
$dbo->setQuery($query);
$ext = $dbo->loadObject();
if (!$ext) { fwrite(STDERR, "LDAP plugin not found.\n"); exit(2); }
// Merge desired params
$desired = [
"host" => getenv('JOOMLA_LDAP_HOST'),
"port" => (int) getenv('JOOMLA_LDAP_PORT'),
"basedn" => getenv('JOOMLA_LDAP_BASE_DN'),
"userbasedn" => getenv('JOOMLA_LDAP_USER_TREE_DN'),
"groupbasedn" => getenv('JOOMLA_LDAP_GROUP_TREE_DN'),
"authmethod" => getenv('JOOMLA_LDAP_AUTH_METHOD'), // "bind" or "search"
"searchstring" => getenv('JOOMLA_LDAP_USER_SEARCH_STRING'),
"username" => getenv('JOOMLA_LDAP_BIND_DN'),
"password" => getenv('JOOMLA_LDAP_BIND_PASSWORD'),
"uid" => getenv('JOOMLA_LDAP_UID_ATTR'),
"email" => getenv('JOOMLA_LDAP_EMAIL_ATTR'),
"fullname" => getenv('JOOMLA_LDAP_NAME_ATTR'),
"starttls" => (bool) getenv('JOOMLA_LDAP_USE_STARTTLS'),
"ignore_reqcert" => (bool) getenv('JOOMLA_LDAP_IGNORE_CERT'),
"mapfullname" => (bool) getenv('JOOMLA_LDAP_MAP_FULLNAME'),
"mapemail" => (bool) getenv('JOOMLA_LDAP_MAP_EMAIL'),
];
$current = json_decode($ext->params ?: "{}", true) ?: [];
$merged = array_replace($current, array_filter($desired, fn($v) => $v !== null && $v !== ''));
$ext->params = json_encode($merged, JSON_UNESCAPED_SLASHES);
$ext->enabled = {{ JOOMLA_LDAP_ENABLED | ternary(1, 0) }};
$dbo->updateObject('#__extensions', $ext, 'extension_id');
echo "LDAP plugin enabled=". $ext->enabled . " and configured.\n";

View File

@@ -1,10 +1,17 @@
{% include 'roles/docker-compose/templates/base.yml.j2' %}
application:
image: "{{ JOOMLA_IMAGE }}:{{ JOOMLA_VERSION }}"
container_name: "{{ JOOMLA_CONTAINER }}"
build:
context: {{ docker_compose.directories.instance }}
dockerfile: Dockerfile
image: "{{ JOOMLA_CUSTOM_IMAGE }}"
container_name: {{ JOOMLA_CONTAINER }}
pull_policy: never
{% include 'roles/docker-container/templates/base.yml.j2' %}
volumes:
- data:/var/www/html
{% if JOOMLA_LDAP_ENABLED %}
- {{ JOOMLA_LDAP_CONF_FILE }}:/var/www/html/cli/cli-ldap.php:ro
{% endif %}
ports:
- "127.0.0.1:{{ ports.localhost.http[application_id] }}:{{ container_port }}"
{% include 'roles/docker-container/templates/healthcheck/curl.yml.j2' %}

View File

@@ -1,4 +1,34 @@
JOOMLA_SITE_NAME={{ JOOMLA_SITE_NAME }}
JOOMLA_ADMIN_USER={{ JOOMLA_USER }}
JOOMLA_ADMIN_USERNAME={{ JOOMLA_USER_NAME }}
JOOMLA_ADMIN_PASSWORD={{ JOOMLA_USER_PASSWORD }}
JOOMLA_ADMIN_EMAIL={{ JOOMLA_USER_EMAIL }}
{% if database_type == 'mariadb' %}
# Database
JOOMLA_DB_HOST="{{ database_host }}:{{ database_port }}"
JOOMLA_DB_USER="{{ database_username }}"
JOOMLA_DB_PASSWORD="{{ database_password }}"
JOOMLA_DB_NAME="{{ database_name }}"
JOOMLA_DB_NAME="{{ database_name }}"
JOOMLA_DB_TYPE="{{ JOOMLA_DB_CONNECTOR }}"
{% endif %}
{% if JOOMLA_LDAP_ENABLED %}
# LDAP
JOOMLA_LDAP_HOST="{{ JOOMLA_LDAP_HOST }}"
JOOMLA_LDAP_PORT="{{ JOOMLA_LDAP_PORT }}"
JOOMLA_LDAP_BASE_DN="{{ JOOMLA_LDAP_BASE_DN }}"
JOOMLA_LDAP_USER_TREE_DN="{{ JOOMLA_LDAP_USER_TREE_DN }}"
JOOMLA_LDAP_GROUP_TREE_DN="{{ JOOMLA_LDAP_GROUP_TREE_DN }}"
JOOMLA_LDAP_UID_ATTR="{{ JOOMLA_LDAP_UID_ATTR }}"
JOOMLA_LDAP_EMAIL_ATTR="{{ JOOMLA_LDAP_EMAIL_ATTR }}"
JOOMLA_LDAP_NAME_ATTR="{{ JOOMLA_LDAP_NAME_ATTR }}"
JOOMLA_LDAP_BIND_DN="{{ JOOMLA_LDAP_BIND_DN }}"
JOOMLA_LDAP_BIND_PASSWORD="{{ JOOMLA_LDAP_BIND_PASSWORD }}"
JOOMLA_LDAP_USE_STARTTLS="{{ JOOMLA_LDAP_USE_STARTTLS | ternary('1','') }}"
JOOMLA_LDAP_IGNORE_CERT="{{ JOOMLA_LDAP_IGNORE_CERT | ternary('1','') }}"
JOOMLA_LDAP_MAP_FULLNAME="{{ JOOMLA_LDAP_MAP_FULLNAME | ternary('1','') }}"
JOOMLA_LDAP_MAP_EMAIL="{{ JOOMLA_LDAP_MAP_EMAIL | ternary('1','') }}"
JOOMLA_LDAP_AUTH_METHOD="{{ JOOMLA_LDAP_AUTH_METHOD }}"
JOOMLA_LDAP_USER_SEARCH_STRING="{{ JOOMLA_LDAP_USER_SEARCH_STRING }}"
{% endif %}