6 Commits

Author SHA1 Message Date
aa1a901309 feat(web-app-drupal): add Drupal role, OIDC config, and wiring
- networks: add web-app-drupal subnet 192.168.104.80/28
- ports: map localhost http port 8060
- add role files: tasks, vars, schema, users, templates (Dockerfile, docker-compose, settings.local.php, upload.ini)
- add docs: README.md and Administration.md

Ref: https://chatgpt.com/share/690535c5-b55c-800f-8556-5335a6b8a33f
2025-10-31 23:19:07 +01:00
d61c81634c Add Joomla CLI paths and implement non-interactive admin password reset via CLI
Ref: https://chatgpt.com/share/69039c22-f530-800f-a641-fd2636d5b6af
2025-10-30 18:11:18 +01:00
265f815b48 Optimized Listmonk and Nextcloud CSP for hcaptcha 2025-10-30 16:02:09 +01:00
f8e5110730 Add Redis readiness check before Nextcloud upgrade and add retry logic for maintenance repair
This prevents OCC repair failures caused by Redis still loading its dataset after container restarts.
See context: https://chatgpt.com/share/690377ba-1520-800f-b8c1-bc93fbd9232f
2025-10-30 15:36:00 +01:00
37b213f96a Refactor XWiki OIDC activation to use REST-based authenticationService update (reliable alternative to Groovy) — see ChatGPT discussion: https://chatgpt.com/share/69005d88-6bf8-800f-af41-73b0e5dc9c13 2025-10-29 11:12:19 +01:00
5ef525eac9 Optimized CSP for Gitlab 2025-10-28 08:26:53 +01:00
32 changed files with 605 additions and 3 deletions

View File

@@ -114,6 +114,8 @@ defaults_networks:
subnet: 192.168.104.48/28
web-app-mini-qr:
subnet: 192.168.104.64/28
web-app-drupal:
subnet: 192.168.104.80/28
# /24 Networks / 254 Usable Clients
web-app-bigbluebutton:

View File

@@ -81,6 +81,7 @@ ports:
web-app-minio_api: 8057
web-app-minio_console: 8058
web-app-mini-qr: 8059
web-app-drupal: 8060
web-app-bigbluebutton: 48087 # This port is predefined by bbb. @todo Try to change this to a 8XXX port
public:
# The following ports should be changed to 22 on the subdomain via stream mapping

View File

@@ -0,0 +1,29 @@
# Administration
## Shell access
```bash
docker-compose exec -it application /bin/bash
```
## Drush (inside the container)
```bash
drush --version
drush cr # Cache rebuild
drush status # Site status
drush cim -y # Config import (if using config sync)
drush updb -y # Run DB updates
```
## Database access (local DB service)
```bash
docker-compose exec -it database /bin/mysql -u drupal -p
```
## Test Email
```bash
docker-compose exec -it application /bin/bash -lc 'echo "Test Email" | sendmail -v your-email@example.com'
```

View File

@@ -0,0 +1,32 @@
# Drupal
## Description
[Drupal](https://www.drupal.org/) is a powerful open-source CMS for building secure, extensible, and content-rich digital experiences.
This role deploys a containerized **Drupal 10/11** instance optimized for production, including **msmtp** for outbound email, **Drush** for CLI administration, and **OpenID Connect (OIDC)** for SSO (e.g., Keycloak, Auth0, Azure AD).
## Overview
* **Flexible Content Model:** Entities, fields, and views for complex data needs.
* **Security & Roles:** Fine-grained access control and active security team.
* **Robust Ecosystem:** Thousands of modules and themes.
* **CLI Automation:** Drush for installs, updates, and configuration import.
* **OIDC SSO:** First-class login via external Identity Providers.
This automated Docker Compose deployment builds a custom Drupal image with Drush and msmtp, wires database credentials and config overrides via environment, and applies OIDC configuration via Ansible/Drush.
## OIDC
This role enables **OpenID Connect** via the `openid_connect` module and configures a **client entity** (e.g., `keycloak`) including endpoints and scopes. Global OIDC behavior (auto-create, link existing users, privacy) is set via `openid_connect.settings`.
## Further Resources
* [Drupal.org](https://www.drupal.org/)
* [OpenID Connect module](https://www.drupal.org/project/openid_connect)
## Credits
Developed and maintained by **Kevin Veen-Birkenbach**
Learn more at [veen.world](https://veen.world)
Part of the [Infinito.Nexus Project](https://s.infinito.nexus/code)
License: [Infinito.Nexus NonCommercial License](https://s.infinito.nexus/license)

View File

@@ -0,0 +1,37 @@
title: "Site"
max_upload_size: "256M"
features:
matomo: true
css: false
desktop: true
oidc: true
central_database: true
logout: true
server:
csp:
flags: {}
whitelist: {}
domains:
canonical:
- "drupal.{{ PRIMARY_DOMAIN }}"
aliases: []
docker:
services:
database:
enabled: true
drupal:
version: latest
image: drupal
name: drupal
backup:
no_stop_required: true
volumes:
data: drupal_data
rbac:
roles:
authenticated:
description: "Logged-in user"
content_editor:
description: "Can create and edit content"
site_admin:
description: "Full site administration"

View File

@@ -0,0 +1,23 @@
galaxy_info:
author: "Kevin Veen-Birkenbach"
description: >
Drupal CMS in Docker with Drush, msmtp, and OpenID Connect (OIDC) SSO.
license: "Infinito.Nexus NonCommercial License"
license_url: "https://s.infinito.nexus/license"
company: |
Kevin Veen-Birkenbach
Consulting & Coaching Solutions
https://www.veen.world
galaxy_tags:
- drupal
- docker
- cms
- oidc
- sso
repository: "https://s.infinito.nexus/code"
issue_tracker_url: "https://s.infinito.nexus/issues"
documentation: "https://docs.infinito.nexus"
logo:
class: "fa-solid fa-droplet"
run_after:
- web-app-keycloak

View File

@@ -0,0 +1,9 @@
credentials:
administrator_password:
description: "Initial password for the Drupal admin account"
algorithm: "sha256"
validation: "^[a-f0-9]{64}$"
hash_salt:
description: "Drupal hash_salt value used for one-time logins, CSRF tokens, etc."
algorithm: "sha256"
validation: "^[a-f0-9]{64}$"

View File

@@ -0,0 +1,25 @@
- name: "Ensure settings.php exists and includes settings.local.php"
command: >
docker exec -u root {{ DRUPAL_CONTAINER }} bash -lc
"set -e;
f='{{ DRUPAL_DOCKER_CONF_PATH }}/settings.php';
df='{{ DRUPAL_DOCKER_CONF_PATH }}/default.settings.php';
if [ ! -f \"$f\" ] && [ -f \"$df\" ]; then
cp \"$df\" \"$f\";
chown www-data:www-data \"$f\";
chmod 644 \"$f\";
fi;
php -r '
$f=\"{{ DRUPAL_DOCKER_CONF_PATH }}/settings.php\";
if (!file_exists($f)) { exit(0); }
$c=file_get_contents($f);
$inc=\"\\nif (file_exists(\\\"\$app_root/\$site_path/settings.local.php\\\")) { include \$app_root/\$site_path/settings.local.php; }\\n\";
if (strpos($c, \"settings.local.php\") === false) {
file_put_contents($f, $c.$inc);
echo \"patched\";
} else {
echo \"exists\";
}
'"
register: settings_local_include
changed_when: "'patched' in settings_local_include.stdout"

View File

@@ -0,0 +1,15 @@
- name: "Run Drupal site:install via Drush"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
command: >
docker exec {{ DRUPAL_CONTAINER }} bash -lc
"/var/www/html/vendor/bin/drush -r {{ DRUPAL_DOCKER_HTML_PATH }} si standard -y
--site-name='{{ applications | get_app_conf(application_id, 'title', True) }}'
--account-name='{{ applications | get_app_conf(application_id, 'users.administrator.username') }}'
--account-mail='{{ applications | get_app_conf(application_id, 'users.administrator.email', True) }}'
--account-pass='{{ applications | get_app_conf(application_id, 'credentials.administrator_password', True) }}'
--uri='{{ DRUPAL_URL }}'"
args:
chdir: "{{ docker_compose.directories.instance }}"
register: drupal_install
changed_when: "'Installation complete' in drupal_install.stdout"
failed_when: false

View File

@@ -0,0 +1,12 @@
- name: "Enable OpenID Connect core module"
command: >
docker exec {{ DRUPAL_CONTAINER }} bash -lc
"/var/www/html/vendor/bin/drush -r {{ DRUPAL_DOCKER_HTML_PATH }} en openid_connect -y"
changed_when: true
- name: "Enable OpenID Connect Keycloak preset (submodule of openid_connect)"
command: >
docker exec {{ DRUPAL_CONTAINER }} bash -lc
"/var/www/html/vendor/bin/drush -r {{ DRUPAL_DOCKER_HTML_PATH }} en openid_connect_client_keycloak -y"
changed_when: true
failed_when: false

View File

@@ -0,0 +1,59 @@
- name: "Load OIDC vars"
include_vars:
file: "{{ role_path }}/vars/oidc.yml"
name: oidc_vars
- name: "Apply openid_connect.settings (global)"
loop: "{{ oidc_vars.oidc_settings | dict2items }}"
loop_control:
label: "{{ item.key }}"
command: >
docker exec {{ DRUPAL_CONTAINER }} bash -lc
"/var/www/html/vendor/bin/drush -r {{ DRUPAL_DOCKER_HTML_PATH }} cset -y
openid_connect.settings {{ item.key }}
{{ (item.value | to_json) if item.value is mapping or item.value is sequence else item.value }}"
- name: "Ensure OIDC client entity exists"
vars:
client_id: "{{ oidc_vars.oidc_client.id }}"
client_label: "{{ oidc_vars.oidc_client.label }}"
command: >
docker exec {{ DRUPAL_CONTAINER }} bash -lc
"/var/www/html/vendor/bin/drush -r {{ DRUPAL_DOCKER_HTML_PATH }} eval '
$id=\"{{ client_id }}\"; $label=\"{{ client_label }}\";
$storage=\Drupal::entityTypeManager()->getStorage(\"openid_connect_client\");
if (!$storage->load($id)) {
$client=$storage->create([\"id\"=>$id,\"label\"=>$label]);
$client->save();
print \"created\";
} else { print \"exists\"; }'"
register: client_exists
changed_when: "'created' in client_exists.stdout"
- name: "Apply OIDC client settings"
vars:
client_id: "{{ oidc_vars.oidc_client.id }}"
settings_map: "{{ oidc_vars.oidc_client.settings }}"
kv: "{{ settings_map | dict2items }}"
loop: "{{ kv }}"
loop_control:
label: "{{ item.key }}"
command: >
docker exec {{ DRUPAL_CONTAINER }} bash -lc
"/var/www/html/vendor/bin/drush -r {{ DRUPAL_DOCKER_HTML_PATH }} eval '
$id=\"{{ client_id }}\";
$key=\"{{ item.key }}\";
$val=json_decode(base64_decode(\"{{ (item.value | to_json | b64encode) }}\"), true);
$storage=\Drupal::entityTypeManager()->getStorage(\"openid_connect_client\");
$c=$storage->load($id);
$s=$c->get(\"settings\");
$s[$key]=$val;
$c->set(\"settings\", $s);
$c->save();'"
changed_when: true
- name: "Clear caches after OIDC config"
command: >
docker exec {{ DRUPAL_CONTAINER }} bash -lc
"/var/www/html/vendor/bin/drush -r {{ DRUPAL_DOCKER_HTML_PATH }} cr"
changed_when: false

View File

@@ -0,0 +1,19 @@
- name: "Set trusted_host_patterns for canonical domains"
vars:
patterns: "{{ DRUPAL_DOMAINS
| map('regex_replace','\\\\.','\\\\\\\\.')
| map('regex_replace','^','^')
| map('regex_replace','$','$')
| list }}"
php_array: "{{ patterns | to_json }}"
command: >
docker exec -u root {{ DRUPAL_CONTAINER }} bash -lc
"php -r '
$f="{{ DRUPAL_DOCKER_CONF_PATH }}/settings.local.php";
$c=file_exists($f)?file_get_contents($f):"<?php\n";
// Remove existing assignment of $settings[\"trusted_host_patterns\"] (if any)
$c=preg_replace(\"/(\\\\$settings\\['trusted_host_patterns'\\]\\s*=).*?;/s\", \"\", $c);
$c.="\n\$settings[\'trusted_host_patterns\'] = ".var_export(json_decode("{{ php_array|e }}", true), true).";\n";
file_put_contents($f,$c);
'"
changed_when: true

View File

@@ -0,0 +1,55 @@
- name: "Include role sys-stk-front-proxy for {{ application_id }}"
include_role:
name: sys-stk-front-proxy
loop: "{{ DRUPAL_DOMAINS }}"
loop_control:
loop_var: domain
vars:
proxy_extra_configuration: "client_max_body_size {{ DRUPAL_MAX_UPLOAD_SIZE }};"
http_port: "{{ ports.localhost.http[application_id] }}"
- name: "Load docker and DB for {{ application_id }}"
include_role:
name: sys-stk-back-stateful
vars:
docker_compose_flush_handlers: false
- name: "Transfer upload.ini to {{ DRUPAL_CONFIG_UPLOAD_ABS }}"
template:
src: upload.ini.j2
dest: "{{ DRUPAL_CONFIG_UPLOAD_ABS }}"
notify:
- docker compose up
- docker compose build
- name: "Transfer msmtprc to {{ DRUPAL_MSMTP_ABS }}"
template:
src: "{{ DRUPAL_MSMTP_SRC }}"
dest: "{{ DRUPAL_MSMTP_ABS }}"
notify: docker compose up
- name: "Transfer settings.local.php overrides"
template:
src: settings.local.php.j2
dest: "{{ DRUPAL_SETTINGS_LOCAL_ABS }}"
notify: docker compose up
- name: Flush handlers to make container ready
meta: flush_handlers
- name: "Ensure settings.php includes settings.local.php"
include_tasks: 01_settings_local_include.yml
- name: "Install Drupal (site:install)"
include_tasks: 02_install.yml
- name: "Enable OIDC modules"
include_tasks: 03_enable_modules.yml
when: applications | get_app_conf(application_id, 'features.oidc')
- name: "Configure OIDC (global + client)"
include_tasks: 04_configure_oidc.yml
when: applications | get_app_conf(application_id, 'features.oidc')
- name: "Harden trusted host patterns"
include_tasks: 05_trusted_hosts.yml

View File

@@ -0,0 +1,75 @@
FROM {{ DRUPAL_IMAGE }}:{{ DRUPAL_VERSION }}
# -------------------------------------------------------------------
# System dependencies (mail support + basic tools)
# -------------------------------------------------------------------
RUN apt-get update && \
apt-get install -y msmtp msmtp-mta git unzip zip less nano curl vim && \
rm -rf /var/lib/apt/lists/*
# -------------------------------------------------------------------
# Install Composer
# -------------------------------------------------------------------
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php composer-setup.php --install-dir=/usr/local/bin --filename=composer \
&& rm composer-setup.php
ENV COMPOSER_ALLOW_SUPERUSER=1
# -------------------------------------------------------------------
# Build Drupal project with Drush + OpenID Connect
# IMPORTANT:
# - The Drupal base image uses /var/www/html as a symlink to /opt/drupal/web
# - Therefore, the actual project root must be placed in /opt/drupal
# -------------------------------------------------------------------
RUN set -eux; \
builddir="$(mktemp -d)"; \
composer create-project --no-interaction --no-ansi --no-progress drupal/recommended-project:^10 "$builddir"; \
composer --working-dir="$builddir" require -n drush/drush:^13 drupal/openid_connect:^1; \
rm -rf /opt/drupal/* /opt/drupal/.[!.]* /opt/drupal/..?* 2>/dev/null || true; \
mkdir -p /opt/drupal; \
cp -a "$builddir"/. /opt/drupal/; \
rm -rf "$builddir"
# -------------------------------------------------------------------
# Make vendor binaries available in PATH
# -------------------------------------------------------------------
ENV PATH="/opt/drupal/vendor/bin:${PATH}"
# -------------------------------------------------------------------
# PHP upload configuration
# -------------------------------------------------------------------
COPY {{ DRUPAL_CONFIG_UPLOAD_REL }} $PHP_INI_DIR/conf.d/
# -------------------------------------------------------------------
# Permissions and ownership fixes
# -------------------------------------------------------------------
RUN set -eux; \
# Ensure all directories are traversable
chmod 755 /var /var/www /opt /opt/drupal; \
# Ensure correct ownership for Drupal files
chown -R www-data:www-data /opt/drupal; \
# Apply default permissions
find /opt/drupal -type d -exec chmod 755 {} +; \
find /opt/drupal -type f -exec chmod 644 {} +; \
# Ensure vendor binaries are executable
if [ -d /opt/drupal/vendor/bin ]; then chmod a+rx /opt/drupal/vendor/bin/*; fi; \
if [ -f /opt/drupal/vendor/drush/drush/drush ]; then chmod a+rx /opt/drupal/vendor/drush/drush/drush; fi; \
# Ensure the docroot (/opt/drupal/web) is accessible
if [ -d /opt/drupal/web ]; then \
chmod 755 /opt/drupal/web; \
find /opt/drupal/web -type d -exec chmod 755 {} +; \
fi; \
# Ensure settings.local.php exists and is owned by www-data
install -o www-data -g www-data -m 640 /dev/null /opt/drupal/web/sites/default/settings.local.php
# -------------------------------------------------------------------
# Runtime defaults
# -------------------------------------------------------------------
USER www-data
WORKDIR /var/www/html # symlink pointing to /opt/drupal/web
# -------------------------------------------------------------------
# Build-time check (optional)
# -------------------------------------------------------------------
RUN drush --version

View File

@@ -0,0 +1,22 @@
{% include 'roles/docker-compose/templates/base.yml.j2' %}
application:
{% include 'roles/docker-container/templates/base.yml.j2' %}
image: {{ DRUPAL_CUSTOM_IMAGE }}
container_name: {{ DRUPAL_CONTAINER }}
{{ lookup('template', 'roles/docker-container/templates/build.yml.j2') | indent(4) }}
ports:
- "127.0.0.1:{{ ports.localhost.http[application_id] }}:80"
volumes:
- data:/var/www/html/web/sites/default/files
- {{ DRUPAL_MSMTP_ABS }}:/etc/msmtprc
- {{ DRUPAL_SETTINGS_LOCAL_ABS }}:{{ DRUPAL_DOCKER_CONF_PATH }}/settings.local.php
{% include 'roles/docker-container/templates/healthcheck/msmtp_curl.yml.j2' %}
{% include 'roles/docker-container/templates/depends_on/dmbs_excl.yml.j2' %}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
{% include 'roles/docker-compose/templates/networks.yml.j2' %}
{% include 'roles/docker-compose/templates/volumes.yml.j2' %}
data:
name: "{{ DRUPAL_VOLUME }}"

View File

@@ -0,0 +1,7 @@
DRUPAL_DB_HOST= "{{ database_host }}:{{ database_port }}"
DRUPAL_DB_USER= "{{ database_username }}"
DRUPAL_DB_PASSWORD= "{{ database_password }}"
DRUPAL_DB_NAME= "{{ database_name }}"
# Debug flags (optional)
DRUPAL_DEBUG={{ MODE_DEBUG | lower }}

View File

@@ -0,0 +1,49 @@
<?php
/**
* Local settings overrides generated by Ansible.
* - Reads DB + OIDC endpoints from environment variables.
* - Sets $databases and selected $config overrides.
*/
$env = getenv();
/** Database **/
$host = getenv('DRUPAL_DB_HOST') ?: '{{ database_host }}:{{ database_port }}';
$db = getenv('DRUPAL_DB_NAME') ?: '{{ database_name }}';
$user = getenv('DRUPAL_DB_USER') ?: '{{ database_username }}';
$pass = getenv('DRUPAL_DB_PASSWORD') ?: '{{ database_password }}';
$parts = explode(':', $host, 2);
$hostname = $parts[0];
$port = isset($parts[1]) ? (int)$parts[1] : 3306;
$databases['default']['default'] = [
'database' => $db,
'username' => $user,
'password' => $pass,
'prefix' => '',
'host' => $hostname,
'port' => $port,
'namespace'=> 'Drupal\\Core\\Database\\Driver\\mysql',
'driver' => 'mysql',
];
/** OIDC endpoint hints (optional) — the real config is applied via Drush. */
$config['openid_connect.settings']['automatic_account_creation'] = true;
$config['openid_connect.settings']['always_save_userinfo'] = true;
$config['openid_connect.settings']['link_existing_users'] = true;
/** Trusted host patterns can be extended by Ansible task 04_trusted_hosts.yml */
/** Enable local services YML if present */
$settings['container_yamls'][] = $app_root . '/' . $site_path . '/services.local.yml';
// Reverse proxy optional über ENV setzen (z.B. "10.0.0.0/8, 172.16.0.0/12")
$proxy = getenv('REVERSE_PROXY_ADDRESSES');
if ($proxy) {
$settings['reverse_proxy'] = TRUE;
$settings['reverse_proxy_addresses'] = array_map('trim', explode(',', $proxy));
}
/** Hash salt (from schema/credentials, hashed with SHA-256) */
$settings['hash_salt'] = '{{ applications | get_app_conf(application_id, "credentials.hash_salt", True) }}';

View File

@@ -0,0 +1,8 @@
file_uploads = On
memory_limit = {{ DRUPAL_MAX_UPLOAD_SIZE }}
upload_max_filesize = {{ DRUPAL_MAX_UPLOAD_SIZE }}
post_max_size = {{ DRUPAL_MAX_UPLOAD_SIZE }}
max_execution_time = 300
; Use msmtp as the Mail Transfer Agent
sendmail_path = "/usr/bin/msmtp -t"

View File

@@ -0,0 +1,4 @@
users:
administrator:
username: "administrator"
email: "administrator@{{ PRIMARY_DOMAIN }}"

View File

@@ -0,0 +1,28 @@
# General
application_id: "web-app-drupal"
database_type: "mariadb"
# Drupal
DRUPAL_URL: "{{ domains | get_url(application_id, WEB_PROTOCOL) }}"
DRUPAL_CUSTOM_IMAGE: "drupal_custom"
DRUPAL_DOCKER_HTML_PATH: "/var/www/html"
DRUPAL_DOCKER_CONF_PATH: "/var/www/html/sites/default"
DRUPAL_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.drupal.version') }}"
DRUPAL_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.drupal.image') }}"
DRUPAL_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.drupal.name') }}"
DRUPAL_VOLUME: "{{ applications | get_app_conf(application_id, 'docker.volumes.data') }}"
DRUPAL_DOMAINS: "{{ applications | get_app_conf(application_id, 'server.domains.canonical') }}"
DRUPAL_USER: "www-data"
DRUPAL_CONFIG_UPLOAD_REL: "config/upload.ini"
DRUPAL_CONFIG_UPLOAD_ABS: "{{ [docker_compose.directories.instance, DRUPAL_CONFIG_UPLOAD_REL] | path_join }}"
DRUPAL_SETTINGS_LOCAL_REL: "config/settings.local.php"
DRUPAL_SETTINGS_LOCAL_ABS: "{{ [docker_compose.directories.instance, DRUPAL_SETTINGS_LOCAL_REL] | path_join }}"
DRUPAL_MSMTP_SRC: "{{ [ playbook_dir, 'roles/sys-svc-msmtp/templates/msmtprc.conf.j2' ] | path_join }}"
DRUPAL_MSMTP_ABS: "{{ [ docker_compose.directories.config, 'msmtprc.conf'] | path_join }}"
DRUPAL_MAX_UPLOAD_SIZE: "{{ applications | get_app_conf(application_id, 'max_upload_size') }}"

View File

@@ -0,0 +1,33 @@
# OIDC configuration for Drupal's OpenID Connect module.
# Global settings for openid_connect.settings
oidc_settings:
automatic_account_creation: true # Auto-create users on first login
always_save_userinfo: true # Store latest userinfo on each login
link_existing_users: true # Match existing users by email
login_display: "button" # 'button' or 'form'
enforced: false # If true, require login for the whole site
# OIDC client entity (e.g., 'keycloak')
oidc_client:
id: "keycloak"
label: "Keycloak"
settings:
client_id: "{{ OIDC.CLIENT.ID }}"
client_secret: "{{ OIDC.CLIENT.SECRET }}"
authorization_endpoint: "{{ OIDC.CLIENT.AUTHORIZE_URL }}"
token_endpoint: "{{ OIDC.CLIENT.TOKEN_URL }}"
userinfo_endpoint: "{{ OIDC.CLIENT.USER_INFO_URL }}"
end_session_endpoint: "{{ OIDC.CLIENT.LOGOUT_URL }}"
scopes:
- "openid"
- "email"
- "profile"
use_standard_claims: true
# Optional claim mapping examples:
# username_claim: "{{ OIDC.ATTRIBUTES.USERNAME }}"
# email_claim: "{{ OIDC.ATTRIBUTES.EMAIL }}"
# given_name_claim: "{{ OIDC.ATTRIBUTES.GIVEN_NAME }}"
# family_name_claim: "{{ OIDC.ATTRIBUTES.FAMILY_NAME }}"

View File

@@ -27,3 +27,7 @@ server:
domains:
canonical:
- lab.git.{{ PRIMARY_DOMAIN }}
csp:
flags:
script-src-elem:
unsafe-inline: true

View File

@@ -11,7 +11,7 @@
# (Optional) specifically wait for the CLI installer script
- name: "Check for CLI installer"
command:
argv: [ docker, exec, "{{ JOOMLA_CONTAINER }}", test, -f, /var/www/html/installation/joomla.php ]
argv: [ docker, exec, "{{ JOOMLA_CONTAINER }}", test, -f, "{{ JOOMLA_INSTALLER_CLI_FILE }}" ]
register: has_installer
changed_when: false
failed_when: false
@@ -32,7 +32,7 @@
- exec
- "{{ JOOMLA_CONTAINER }}"
- php
- /var/www/html/installation/joomla.php
- "{{ JOOMLA_INSTALLER_CLI_FILE }}"
- install
- "--db-type={{ JOOMLA_DB_CONNECTOR }}"
- "--db-host={{ database_host }}"

View File

@@ -0,0 +1,18 @@
---
# Reset Joomla admin password via CLI (inside the container)
- name: "Reset Joomla admin password (non-interactive CLI)"
command:
argv:
- docker
- exec
- "{{ JOOMLA_CONTAINER }}"
- php
- "{{ JOOMLA_CLI_FILE }}"
- user:reset-password
- "--username"
- "{{ JOOMLA_USER_NAME }}"
- "--password"
- "{{ JOOMLA_USER_PASSWORD }}"
register: j_password_reset
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
changed_when: j_password_reset.rc == 0

View File

@@ -24,3 +24,7 @@
- name: Include assert routines
include_tasks: "04_assert.yml"
when: MODE_ASSERT | bool
- name: Reset Admin Password
include_tasks: 05_reset_admin_password.yml

View File

@@ -13,6 +13,8 @@ JOOMLA_DOMAINS: "{{ applications | get_app_conf(application_id
JOOMLA_SITE_NAME: "{{ SOFTWARE_NAME }} Joomla - CMS"
JOOMLA_DB_CONNECTOR: "{{ 'pgsql' if database_type == 'postgres' else 'mysqli' }}"
JOOMLA_CONFIG_FILE: "/var/www/html/configuration.php"
JOOMLA_INSTALLER_CLI_FILE: "/var/www/html/installation/joomla.php"
JOOMLA_CLI_FILE: "/var/www/html/cli/joomla.php"
# User
JOOMLA_USER_NAME: "{{ users.administrator.username }}"

View File

@@ -13,6 +13,16 @@ server:
aliases: []
status_codes:
default: 404
csp:
flags:
script-src-elem:
unsafe-inline: true
whitelist:
script-src-elem:
- "https://www.hcaptcha.com"
- "https://js.hcaptcha.com"
frame-src:
- "https://newassets.hcaptcha.com/"
docker:
services:
database:

View File

@@ -9,6 +9,9 @@ server:
script-src-attr:
unsafe-eval: true
whitelist:
script-src-elem:
- "https://www.hcaptcha.com"
- "https://js.hcaptcha.com"
font-src:
- "data:"
connect-src:
@@ -19,6 +22,7 @@ server:
frame-src:
- "{{ WEBSOCKET_PROTOCOL }}://collabora.{{ PRIMARY_DOMAIN }}"
- "{{ WEB_PROTOCOL }}://collabora.{{ PRIMARY_DOMAIN }}"
- "https://newassets.hcaptcha.com/"
worker-src:
- "blob:"
domains:

View File

@@ -7,6 +7,9 @@
command: "{{ NEXTCLOUD_DOCKER_EXEC_OCC }} maintenance:repair --include-expensive"
register: occ_repair
changed_when: "'No repairs needed' not in occ_repair.stdout"
retries: 3
delay: 10
until: occ_repair.rc == 0
- name: Nextcloud | App update (retry once)
command: "{{ NEXTCLOUD_DOCKER_EXEC_OCC }} app:update --all"

View File

@@ -16,6 +16,13 @@
- name: Flush all handlers immediately so that occ can be used
meta: flush_handlers
- name: Wait until Redis is ready (PONG)
command: "docker exec {{ NEXTCLOUD_REDIS_CONTAINER }} redis-cli ping"
register: redis_ping
retries: 60
delay: 2
until: (redis_ping.stdout | default('')) is search('PONG')
- name: Update\Upgrade Nextcloud
include_tasks: 03_upgrade.yml
when: MODE_UPDATE | bool

View File

@@ -141,4 +141,7 @@ NEXTCLOUD_DOCKER_USER: "www-data" # Name of the www-data user
## Execution
NEXTCLOUD_INTERNAL_OCC_COMMAND: "{{ [ NEXTCLOUD_DOCKER_WORK_DIRECTORY, 'occ'] | path_join }}"
NEXTCLOUD_DOCKER_EXEC: "docker exec -u {{ NEXTCLOUD_DOCKER_USER }} {{ NEXTCLOUD_CONTAINER }}" # General execute composition
NEXTCLOUD_DOCKER_EXEC_OCC: "{{ NEXTCLOUD_DOCKER_EXEC }} {{ NEXTCLOUD_INTERNAL_OCC_COMMAND }}" # Execute docker occ command
NEXTCLOUD_DOCKER_EXEC_OCC: "{{ NEXTCLOUD_DOCKER_EXEC }} {{ NEXTCLOUD_INTERNAL_OCC_COMMAND }}" # Execute docker occ command
## Redis
NEXTCLOUD_REDIS_CONTAINER: "{{ entity_name }}-redis"

View File

@@ -9,9 +9,11 @@
environment:
JAVA_OPTS: >-
{% if xwiki_oidc_enabled_switch| bool %}
-Dxwiki.authentication.authservice=oidc
-Dxwiki.authentication.authclass=org.xwiki.contrib.oidc.auth.OIDCAuthServiceImpl
{% elif xwiki_ldap_enabled_switch | bool %}
-Dxwiki.authentication.authclass=org.xwiki.contrib.ldap.XWikiLDAPAuthServiceImpl
-Dxwiki.authentication.authservice=ldap
-Dxwiki.authentication.ldap=1
-Dxwiki.authentication.ldap.trylocal={{ (XWIKI_LDAP_TRYLOCAL | bool) | ternary(1, 0) }}
-Dxwiki.authentication.ldap.group_mapping=XWiki.XWikiAdminGroup={{ XWIKI_LDAP_ADMIN_GROUP_DN }}
@@ -24,6 +26,7 @@
-Dxwiki.authentication.ldap.fields_mapping={{ XWIKI_LDAP_FIELDS_MAPPING }}
-Dxwiki.authentication.ldap.update_user=1
{% else %}
-Dxwiki.authentication.authservice=standard
-Dxwiki.authentication.authclass=com.xpn.xwiki.user.impl.xwiki.XWikiAuthServiceImpl
{% endif %}
volumes: