From f106d5ec36bf2cd1c714a645a868cef29e464a87 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Fri, 12 Sep 2025 15:50:30 +0200 Subject: [PATCH] web-app-xwiki: admin bootstrap & REST/extension install fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Guard admin tasks via XWIKI_SSO_ENABLED • Create admin using XWikiUsers object API • Wait for REST without DW redirect • Install OIDC/LDAP via /rest/jobs (+verify) • Mount xwiki.cfg/properties under Tomcat WEB-INF • Build REST URLs with url_join; enable DW auto bootstrap + repos https://chatgpt.com/share/68c42502-a5cc-800f-b05a-a1dbe48f014d --- roles/web-app-xwiki/tasks/01_core.yml | 1 + .../web-app-xwiki/tasks/03_administrator.yml | 84 +++++++++++++------ roles/web-app-xwiki/tasks/04_extensions.yml | 25 +++++- roles/web-app-xwiki/tasks/_flush_config.yml | 11 ++- .../templates/docker-compose.yml.j2 | 2 + .../templates/xwiki.properties.j2 | 20 ++++- roles/web-app-xwiki/vars/main.yml | 7 +- 7 files changed, 108 insertions(+), 42 deletions(-) diff --git a/roles/web-app-xwiki/tasks/01_core.yml b/roles/web-app-xwiki/tasks/01_core.yml index 2fef94f5..91ad33c7 100644 --- a/roles/web-app-xwiki/tasks/01_core.yml +++ b/roles/web-app-xwiki/tasks/01_core.yml @@ -16,6 +16,7 @@ - name: Load setup procedures for admin include_tasks: 03_administrator.yml + when: not (XWIKI_SSO_ENABLED | bool) - name: Load setup procedures for extensions include_tasks: 04_extensions.yml diff --git a/roles/web-app-xwiki/tasks/03_administrator.yml b/roles/web-app-xwiki/tasks/03_administrator.yml index b970cee1..4b4d1704 100644 --- a/roles/web-app-xwiki/tasks/03_administrator.yml +++ b/roles/web-app-xwiki/tasks/03_administrator.yml @@ -1,43 +1,73 @@ ---- -# Wait until REST endpoint is available (01_core usually ensures this, but add safety) -- name: "XWIKI | Wait until REST answers" +# 1) Create page XWiki. (PUT is idempotent) +- name: "XWIKI | Ensure user page exists: XWiki.{{ XWIKI_ADMIN_USER }}" uri: - url: "{{ XWIKI_REST_BASE }}" - status_code: [200, 401] - register: _rest_ping - retries: 60 - delay: 5 - until: _rest_ping is succeeded + url: "{{ XWIKI_REST_BASE }}wikis/xwiki/spaces/XWiki/pages/{{ XWIKI_ADMIN_USER | urlencode }}" + method: PUT + user: "{{ XWIKI_SUPERADMIN_USERNAME }}" + password: "{{ XWIKI_SUPERADMIN_PASSWORD }}" + force_basic_auth: true + status_code: [201, 202, 204, 200] + headers: + Content-Type: "application/xml" + Accept: "application/xml" + body: | + + {{ XWIKI_ADMIN_USER }} + + register: _user_page -# Check if the target admin already exists -# 404 => missing, 302 => DW redirect (treat as missing for bootstrap) -- name: "XWIKI | Check if target admin user exists" +# 2) Add XWiki.XWikiUsers object (only if it does not already exist) +- name: "XWIKI | Check if XWikiUsers object exists" uri: - url: "{{ XWIKI_REST_XWIKI }}/users/{{ XWIKI_ADMIN_USER | urlencode }}" + url: "{{ XWIKI_REST_BASE }}wikis/xwiki/spaces/XWiki/pages/{{ XWIKI_ADMIN_USER | urlencode }}/objects?classname=XWiki.XWikiUsers" method: GET user: "{{ XWIKI_SUPERADMIN_USERNAME }}" password: "{{ XWIKI_SUPERADMIN_PASSWORD }}" force_basic_auth: true - status_code: [200, 404, 302] - register: _admin_exists + status_code: [200, 404] + register: _users_obj_list -# Create admin user if not existing (or DW still redirecting) -- name: "XWIKI | Create admin user via REST" +- name: "XWIKI | Add XWiki.XWikiUsers object" uri: - url: "{{ XWIKI_REST_XWIKI }}/users" + url: "{{ XWIKI_REST_BASE }}wikis/xwiki/spaces/XWiki/pages/{{ XWIKI_ADMIN_USER | urlencode }}/objects" method: POST user: "{{ XWIKI_SUPERADMIN_USERNAME }}" password: "{{ XWIKI_SUPERADMIN_PASSWORD }}" force_basic_auth: true - status_code: 201 + status_code: [201, 200] headers: Content-Type: "application/xml" + Accept: "application/xml" body: | - - {{ users.administrator.firstname | default('Admin') }} - {{ users.administrator.lastname | default('User') }} - {{ users.administrator.email }} - {{ XWIKI_ADMIN_USER }} - {{ XWIKI_ADMIN_PASS }} - - when: _admin_exists.status in [404, 302] + + XWiki.XWikiUsers + + {{ users.administrator.firstname | default('Admin') }} + {{ users.administrator.lastname | default('User') }} + {{ users.administrator.email }} + 1 + + + when: _users_obj_list.status == 404 or (' + XWiki.XWikiGroups + + XWiki.{{ XWIKI_ADMIN_USER }} + + + when: XWIKI_LDAP_ENABLED | bool == false and XWIKI_OIDC_ENABLED | bool == false diff --git a/roles/web-app-xwiki/tasks/04_extensions.yml b/roles/web-app-xwiki/tasks/04_extensions.yml index c140c099..38c2fe27 100644 --- a/roles/web-app-xwiki/tasks/04_extensions.yml +++ b/roles/web-app-xwiki/tasks/04_extensions.yml @@ -24,15 +24,32 @@ - name: "Install LDAP and/or OIDC extensions" uri: - url: "{{ XWIKI_REST_EXTENSION_INSTALL }}" + url: "{{ XWIKI_REST_EXTENSION_INSTALL }}?jobType=install&async=false" method: PUT user: "{{ XWIKI_SUPERADMIN_USERNAME }}" password: "{{ XWIKI_SUPERADMIN_PASSWORD }}" force_basic_auth: yes - headers: { Content-Type: "text/xml" } + headers: + Content-Type: "text/xml" + Accept: "application/xml" + X-Requested-With: "XMLHttpRequest" body: "{{ lookup('template', 'installjobrequest.xml.j2') }}" - status_code: 200 + status_code: [200, 202] when: - (XWIKI_OIDC_ENABLED | bool and xwiki_oidc_ext.status == 404) or (XWIKI_LDAP_ENABLED | bool and (xwiki_ldap_ext is not skipped) and xwiki_ldap_ext.status == 404) - no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" \ No newline at end of file + no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" + +- name: "Verify OIDC extension is installed" + when: XWIKI_OIDC_ENABLED | bool + uri: + url: "{{ XWIKI_REST_XWIKI }}/extensions/{{ XWIKI_EXT_OIDC_ID | urlencode }}" + method: GET + user: "{{ XWIKI_SUPERADMIN_USERNAME }}" + password: "{{ XWIKI_SUPERADMIN_PASSWORD }}" + force_basic_auth: yes + status_code: 200 + register: _oidc_ok + retries: 12 + delay: 5 + until: _oidc_ok is succeeded diff --git a/roles/web-app-xwiki/tasks/_flush_config.yml b/roles/web-app-xwiki/tasks/_flush_config.yml index 2ef129f2..557fa99e 100644 --- a/roles/web-app-xwiki/tasks/_flush_config.yml +++ b/roles/web-app-xwiki/tasks/_flush_config.yml @@ -13,13 +13,16 @@ - name: "flush docker compose for '{{ application_id }}'" meta: flush_handlers -- name: "Wait until XWiki REST is ready" +- name: "Wait until XWiki REST is ready (no DW redirect)" uri: url: "{{ XWIKI_REST_BASE }}" - status_code: [200, 401, 302] + status_code: [200, 401] return_content: no - changed_when: false + follow_redirects: none register: xwiki_rest_up + changed_when: false retries: 60 delay: 5 - until: xwiki_rest_up is succeeded \ No newline at end of file + until: + - xwiki_rest_up is succeeded + - (xwiki_rest_up.redirected is not defined) or (not xwiki_rest_up.redirected) diff --git a/roles/web-app-xwiki/templates/docker-compose.yml.j2 b/roles/web-app-xwiki/templates/docker-compose.yml.j2 index f069f242..f4168743 100644 --- a/roles/web-app-xwiki/templates/docker-compose.yml.j2 +++ b/roles/web-app-xwiki/templates/docker-compose.yml.j2 @@ -9,6 +9,8 @@ ports: - "127.0.0.1:{{ XWIKI_HOST_PORT }}:{{ container_port }}" volumes: + - "{{ XWIKI_HOST_CONF_PATH }}:/usr/local/tomcat/webapps/ROOT/WEB-INF/xwiki.cfg" + - "{{ XWIKI_HOST_PROPERTIES_PATH }}:/usr/local/tomcat/webapps/ROOT/WEB-INF/xwiki.properties" - "{{ XWIKI_HOST_CONF_PATH }}:/usr/local/xwiki/xwiki.cfg" - "{{ XWIKI_HOST_PROPERTIES_PATH }}:/usr/local/xwiki/xwiki.properties" - 'data:/usr/local/xwiki' diff --git a/roles/web-app-xwiki/templates/xwiki.properties.j2 b/roles/web-app-xwiki/templates/xwiki.properties.j2 index 9e67f7a8..356a6d4e 100644 --- a/roles/web-app-xwiki/templates/xwiki.properties.j2 +++ b/roles/web-app-xwiki/templates/xwiki.properties.j2 @@ -16,7 +16,19 @@ oidc.groups.mapping=XWiki.XWikiAdminGroup={{ XWIKI_OIDC_ADMIN_PROVIDER_GROUP }} {% endif %} ############################################ -# Distribution Wizard -# Disable automatic start so REST is reachable during automation -distribution.automaticStartOnMainWiki=false -distribution.automaticStartOnWiki=false +# Distribution Wizard (bootstrap) +{% if xwiki_superadmin_enabled_switch | bool %} +# Start DW automatisch und ohne Interaktion +distribution.automaticStartOnMainWiki=true +distribution.automaticStartOnWiki=true +distribution.job.interactive=false +# Standard-Flavor für Main Wiki (XWiki Standard) +distribution.defaultUI=org.xwiki.platform:xwiki-platform-distribution-flavor-mainwiki +{% endif %} + +# Keep data in the Docker volume +environment.permanentDirectory=/usr/local/xwiki/data + +# Make sure Extension Manager can fetch artifacts +extension.repositories=maven:xwiki-public https://nexus.xwiki.org/nexus/content/groups/public/,\ +maven:central https://repo1.maven.org/maven2/ \ No newline at end of file diff --git a/roles/web-app-xwiki/vars/main.yml b/roles/web-app-xwiki/vars/main.yml index 050a7ea9..918a8bf7 100644 --- a/roles/web-app-xwiki/vars/main.yml +++ b/roles/web-app-xwiki/vars/main.yml @@ -26,6 +26,7 @@ XWIKI_DATA_VOLUME: "{{ applications | get_app_conf(applicatio # Feature toggles (must be set in config/main.yml -> features) XWIKI_LDAP_ENABLED: "{{ applications | get_app_conf(application_id, 'features.ldap') }}" XWIKI_OIDC_ENABLED: "{{ applications | get_app_conf(application_id, 'features.oidc') }}" +XWIKI_SSO_ENABLED: "{{ (XWIKI_OIDC_ENABLED | bool) or (XWIKI_LDAP_ENABLED | bool) }}" # Admin credentials (must be provided via inventory/vault) XWIKI_ADMIN_USER: "{{ users.administrator.username }}" @@ -37,9 +38,9 @@ XWIKI_SUPERADMIN_PASSWORD: "{{ applications | get_app_conf(applicatio XWIKI_SUPERADMIN_USERNAME: "superadmin" # REST endpoint (local inside container) -XWIKI_REST_BASE: "http://127.0.0.1:{{ XWIKI_HOST_PORT }}/xwiki/rest/" -XWIKI_REST_EXTENSION_INSTALL: "{{ XWIKI_REST_BASE }}jobs?jobType=install&async=false" -XWIKI_REST_XWIKI: "{{ XWIKI_REST_BASE }}wikis/xwiki" +XWIKI_REST_BASE: "{{ ['http://127.0.0.1:'~ XWIKI_HOST_PORT, '/rest/'] | url_join }}" +XWIKI_REST_EXTENSION_INSTALL: "{{ [XWIKI_REST_BASE, 'jobs'] | url_join }}" +XWIKI_REST_XWIKI: "{{ [XWIKI_REST_BASE, 'wikis/xwiki'] | url_join }}" # Extension IDs + Versions (pin versions explicitly) XWIKI_EXT_LDAP_ID: "org.xwiki.contrib.ldap:ldap-authenticator"