Refactored CyMaIS basic features and optimized wordpress implementation

This commit is contained in:
2025-04-18 23:17:29 +02:00
parent ec5beff22f
commit f8c984d6c2
56 changed files with 1262 additions and 325 deletions

View File

@@ -161,7 +161,7 @@ OFFICE365_HD=
# It is useful for cases when Greenlight is deployed behind a Network Load Balancer or proxy
OAUTH2_REDIRECT=
{% if applications[application_id].ldap.enabled | bool %}
{% if applications[application_id].features.ldap | bool %}
# LDAP Login Provider (optional)
#
# You can enable LDAP authentication by providing values for the variables below.
@@ -286,7 +286,7 @@ HELP_URL=https://docs.bigbluebutton.org/greenlight/gl-overview.html
# approval - For approve/decline registration
DEFAULT_REGISTRATION=invite
{% if applications[application_id].oidc.enabled | bool %}
{% if applications[application_id].features.oidc | bool %}
### EXTERNAL AUTHENTICATION METHODS
# @See https://docs.bigbluebutton.org/greenlight/v3/external-authentication/
#

View File

@@ -16,12 +16,12 @@
src: "env/{{database_type}}.env.j2"
dest: "{{database_env}}"
notify: docker compose project build and setup
when: not applications[application_id].database.central_storage | bool
when: not applications[application_id].features.database | bool
- name: "Create central database"
include_role:
name: "docker-{{database_type}}"
when: applications[application_id].database.central_storage | bool
when: applications[application_id].features.database | bool
- name: "Add database to backup"
include_tasks: "{{ playbook_dir }}/roles/backup-docker-to-local/tasks/seed-database-to-backup.yml"

View File

@@ -1,5 +1,5 @@
# This template needs to be included in docker-compose.yml, which depend on a mariadb database
{% if not applications[application_id].database.central_storage | bool %}
{% if not applications[application_id].features.database | bool %}
database:
container_name: {{application_id}}-database
logging:

View File

@@ -1,5 +1,5 @@
# This template needs to be included in docker-compose.yml, which depend on a postgres database
{% if not applications[application_id].database.central_storage | bool %}
{% if not applications[application_id].features.database | bool %}
database:
image: postgres:{{applications.postgres.version}}-alpine
container_name: {{application_id}}-database

View File

@@ -1,5 +1,5 @@
database_instance: "{{ 'central-' + database_type if applications[application_id].database.central_storage | bool else application_id }}"
database_host: "{{ 'central-' + database_type if applications[application_id].database.central_storage | bool else 'database' }}"
database_instance: "{{ 'central-' + database_type if applications[application_id].features.database | bool else application_id }}"
database_host: "{{ 'central-' + database_type if applications[application_id].features.database | bool else 'database' }}"
database_name: "{{ application_id }}"
database_username: "{{ application_id }}"
database_port: "{{ 3306 if database_type == 'mariadb' else 5432 }}"

View File

@@ -11,7 +11,7 @@
command:
cmd: "docker network connect {{applications.discourse.network}} central-{{ database_type }}"
ignore_errors: true
when: applications[application_id].database.central_storage | bool
when: applications[application_id].features.database | bool
listen: recreate discourse
- name: rebuild discourse

View File

@@ -68,10 +68,10 @@
command:
cmd: "docker network connect central_postgres {{applications.discourse.container}}"
ignore_errors: true
when: applications[application_id].database.central_storage | bool
when: applications[application_id].features.database | bool
- name: "remove central database from {{application_id}}_default"
command:
cmd: "docker network disconnect {{applications.discourse.network}} central-{{ database_type }}"
ignore_errors: true
when: applications[application_id].database.central_storage | bool
when: applications[application_id].features.database | bool

View File

@@ -1,5 +1,5 @@
templates:
{% if not applications[application_id].database.central_storage | bool %}
{% if not applications[application_id].features.database | bool %}
- "templates/postgres.template.yml"
{% endif %}
#- "templates/redis.template.yml"
@@ -112,7 +112,7 @@ run:
## If you want to set the 'From' email address for your first registration, uncomment and change:
## After getting the first signup email, re-comment the line. It only needs to run once.
#- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
{% if applications[application_id].oidc.enabled | bool %}
{% if applications[application_id].features.oidc | bool %}
# Deactivate Default Login
- exec: rails r "SiteSetting.enable_local_logins = false"
- exec: rails r "SiteSetting.enable_passkeys = false" # https://meta.discourse.org/t/passwordless-login-using-passkeys/285589

View File

@@ -1,4 +1,4 @@
application_id: "friendica"
database_password: "{{friendica_database_password}}"
database_type: "mariadb"
no_validation: "{{applications[application_id].oidc.enabled}}" # Email validation is not neccessary if OIDC is active
no_validation: "{{applications[application_id].features.oidc}}" # Email validation is not neccessary if OIDC is active

View File

@@ -100,7 +100,7 @@ DJANGO_SETTINGS_MODULE=config.settings.production
# Generate one using `openssl rand -base64 45`, for example
DJANGO_SECRET_KEY={{funkwhale_django_secret}}
{% if applications[application_id].ldap.enabled | bool %}
{% if applications[application_id].features.ldap | bool %}
# LDAP settings
# Use the following options to allow authentication on your Funkwhale instance
# using a LDAP directory.

View File

@@ -151,14 +151,14 @@ API_TOKEN={{applications.mailu.credentials.api_token}}
AUTH_REQUIRE_TOKENS=True
{% if applications[application_id].oidc.enabled | bool %}
{% if applications[application_id].features.oidc | bool %}
###################################
# OpenID Connect settings
###################################
# @see https://github.com/heviat/Mailu-OIDC/tree/master
# Enable OpenID Connect. Possible values: True, False
OIDC_ENABLED={{ applications[application_id].oidc.enabled | string | capitalize }}
OIDC_ENABLED={{ applications[application_id].features.oidc | string | capitalize }}
# OpenID Connect provider configuration URL
OIDC_PROVIDER_INFO_URL={{oidc.client.issuer_url}}
@@ -182,7 +182,7 @@ OIDC_CHANGE_PASSWORD_REDIRECT_ENABLED=True
# Redirect URL for password change. Defaults to provider issuer url appended by /.well-known/change-password
OIDC_CHANGE_PASSWORD_REDIRECT_URL={{oidc.client.change_credentials}}
{% if applications[application_id].oidc.enabled | bool %}
{% if applications[application_id].features.oidc | bool %}
# The OIDC claim used as the username. If the selected claim contains an email address, it will be used as is. If it is not an email (e.g., sub), the email address will be constructed as <OIDC_USERNAME_CLAIM>@<OIDC_USER_DOMAIN>. Defaults to email.
OIDC_USERNAME_CLAIM={{oidc.attributes.username}}

View File

@@ -6,7 +6,7 @@ enable_wildcard_certificate: false
# Use dedicated source for oidc if activated
# @see https://github.com/heviat/Mailu-OIDC/tree/2024.06
docker_source: "{{ 'ghcr.io/heviat' if applications[application_id].oidc.enabled | bool else 'ghcr.io/mailu' }}"
docker_source: "{{ 'ghcr.io/heviat' if applications[application_id].features.oidc | bool else 'ghcr.io/mailu' }}"
domain: "{{ domains[application_id] }}"
http_port: "{{ ports.localhost.http[application_id] }}"

View File

@@ -52,14 +52,14 @@ SMTP_OPENSSL_VERIFY_MODE=none
SMTP_ENABLE_STARTTLS=auto
SMTP_FROM_ADDRESS=Mastodon <{{system_email.from}}>
{% if applications[application_id].oidc.enabled | bool %}
{% if applications[application_id].features.oidc | bool %}
###################################
# OpenID Connect settings
###################################
# @see https://github.com/mastodon/mastodon/pull/16221
# @see https://stackoverflow.com/questions/72081776/how-mastodon-configured-login-using-sso
OIDC_ENABLED={{ applications[application_id].oidc.enabled | string | lower }}
OIDC_ENABLED={{ applications[application_id].features.oidc | string | lower }}
OIDC_DISPLAY_NAME="{{oidc.button_text}}"
OIDC_ISSUER={{oidc.client.issuer_url}}
OIDC_DISCOVERY=true

View File

@@ -7,7 +7,7 @@
- name: "create {{database_name}} database"
include_role:
name: docker-postgres
when: applications[application_id].database.central_storage | bool
when: applications[application_id].features.database | bool
- name: "include seed-database-to-backup.yml"
include_tasks: "{{ playbook_dir }}/roles/backup-docker-to-local/tasks/seed-database-to-backup.yml"

View File

@@ -45,7 +45,7 @@ email:
client_base_url: "{{domains.matrix_synapse}}"
validation_token_lifetime: 15m
{% if applications[application_id].oidc.enabled | bool %}
{% if applications[application_id].features.oidc | bool %}
# @See https://matrix-org.github.io/synapse/latest/openid.html
oidc_providers:
- idp_id: keycloak

View File

@@ -146,7 +146,7 @@ return array (
//
// The `id` attribute in `oidc_login_attributes` must return the
// "Internal Username" (see expert settings in LDAP integration)
'oidc_login_proxy_ldap' => {{applications[application_id].ldap.enabled | string | lower}},
'oidc_login_proxy_ldap' => {{applications[application_id].features.ldap | string | lower}},
// Disable creation of users new to Nextcloud from OIDC login.
// A user may be known to the IdP but not (yet) known to Nextcloud.

View File

@@ -59,4 +59,4 @@
- name: Setup LDAP
include_tasks: ldap.yml
when: applications[application_id].ldap.enabled | bool
when: applications[application_id].features.ldap | bool

View File

@@ -1,6 +1,6 @@
application_id: "pgadmin"
database_type: "postgres"
database_host: "{{ 'central-' + database_type if applications[application_id].database.central_storage }}"
database_host: "{{ 'central-' + database_type if applications[application_id].features.database }}"
database_var_file: "{{playbook_dir}}/roles/docker-central-database/vars/database.yml"
pgadmin_user: 5050
pgadmin_group: "{{pgadmin_user}}"

View File

@@ -1,3 +1,3 @@
application_id: "phpmyadmin"
database_type: "mariadb"
database_host: "{{ 'central-' + database_type if applications[application_id].database.central_storage}}"
database_host: "{{ 'central-' + database_type if applications[application_id].features.database}}"

View File

@@ -22,7 +22,7 @@ class LookupModule(LookupBase):
- Retrieves the icon class from galaxy_info.logo.class
- Retrieves the tags from galaxy_info.galaxy_tags
- Builds the URL using the 'domains' variable (e.g. domains[application_id])
- Sets the iframe flag from applications[application_id].landingpage_iframe_enabled
- Sets the iframe flag from applications[application_id].features.iframe
Only cards whose application_id is included in the variable group_names are returned.
"""
@@ -98,7 +98,7 @@ class LookupModule(LookupBase):
url = "https://" + domain_url if domain_url else ""
app_data = applications.get(application_id, {})
iframe = app_data.get("landingpage_iframe_enabled", False)
iframe = app_data.get("features", {}).get("iframe", False)
# Build card dictionary
card = {

View File

@@ -28,7 +28,7 @@ accounts:
class: fa-brands fa-mastodon
url: "https://{{ service_provider.contact.mastodon.split('@')[2] }}/@{{ service_provider.contact.mastodon.split('@')[1] }}"
identifier: "{{service_provider.contact.mastodon}}"
iframe: {{ applications | get_landingpage_iframe_enabled('mastodon') }}
iframe: {{ applications | get_features_iframe('mastodon') }}
{% endif %}
{% if service_provider.contact.bluesky is defined and service_provider.contact.bluesky != "" %}
@@ -52,7 +52,7 @@ accounts:
class: fa-solid fa-camera
identifier: "{{service_provider.contact.pixelfed}}"
url: "https://{{ service_provider.contact.pixelfed.split('@')[2] }}/@{{ service_provider.contact.pixelfed.split('@')[1] }}"
iframe: {{ applications | get_landingpage_iframe_enabled('pixelfed') }}
iframe: {{ applications | get_features_iframe('pixelfed') }}
{% endif %}
{% if service_provider.contact.peertube is defined and service_provider.contact.peertube != "" %}
@@ -64,7 +64,7 @@ accounts:
class: fa-solid fa-video
identifier: "{{service_provider.contact.peertube}}"
url: "https://{{ service_provider.contact.peertube.split('@')[2] }}/@{{ service_provider.contact.peertube.split('@')[1] }}"
iframe: {{ applications | get_landingpage_iframe_enabled('peertube') }}
iframe: {{ applications | get_features_iframe('peertube') }}
{% endif %}
{% if service_provider.contact.wordpress is defined and service_provider.contact.wordpress != "" %}
@@ -76,7 +76,7 @@ accounts:
class: fa-solid fa-blog
identifier: "{{service_provider.contact.wordpress}}"
url: "https://{{ service_provider.contact.wordpress.split('@')[2] }}/@{{ service_provider.contact.wordpress.split('@')[1] }}"
iframe: {{ applications | get_landingpage_iframe_enabled('wordpress') }}
iframe: {{ applications | get_features_iframe('wordpress') }}
{% endif %}
{% if service_provider.contact.source_code is defined and service_provider.contact.source_code != "" %}
@@ -98,7 +98,7 @@ accounts:
class: fas fa-network-wired
identifier: "{{service_provider.contact.friendica}}"
url: "https://{{ service_provider.contact.friendica.split('@')[2] }}/@{{ service_provider.contact.friendica.split('@')[1] }}"
iframe: {{ applications | get_landingpage_iframe_enabled('friendica') }}
iframe: {{ applications | get_features_iframe('friendica') }}
{% endif %}

View File

@@ -37,13 +37,13 @@
icon:
class: fa-solid fa-shield-halved
url: https://{{domains.keycloak}}/admin
iframe: {{ applications | get_landingpage_iframe_enabled('keycloak') }}
iframe: {{ applications | get_features_iframe('keycloak') }}
- name: Profile
description: Update your personal admin settings
icon:
class: fa-solid fa-user-gear
url: https://{{ domains.keycloak }}/realms/{{oidc.client.id}}/account
iframe: {{ applications | get_landingpage_iframe_enabled('keycloak') }}
iframe: {{ applications | get_features_iframe('keycloak') }}
- name: Logout
description: End your admin session securely
icon:
@@ -113,7 +113,7 @@
icon:
class: fas fa-book
url: https://{{domains.sphinx}}
iframe: {{ applications | get_landingpage_iframe_enabled('sphinx') }}
iframe: {{ applications | get_features_iframe('sphinx') }}
{% endif %}
@@ -124,7 +124,7 @@
icon:
class: "fas fa-chalkboard-teacher"
url: https://{{domains.presentation}}
iframe: {{ applications | get_landingpage_iframe_enabled('presentation') }}
iframe: {{ applications | get_features_iframe('presentation') }}
{% endif %}

View File

@@ -27,7 +27,7 @@ DB_DATABASE={{database_name}}
DB_USERNAME={{database_username}}
DB_PASSWORD={{database_password}}
{% if not applications[application_id].database.central_storage | bool %}
{% if not applications[application_id].features.database | bool %}
MYSQL_ROOT_PASSWORD={{database_password}}
DB_PREFIX=null
DB_DUMP_PATH='/usr/bin'

View File

@@ -18,7 +18,7 @@
template:
src: "taiga/{{item}}.py.j2"
dest: "{{ docker_compose.directories.config }}taiga-{{item}}.py"
when: applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'taigaio'
when: applications[application_id].features.oidc and applications[application_id].oidc.flavor == 'taigaio'
notify: docker compose project build and setup
loop: "{{ settings_files }}"

View File

@@ -9,7 +9,7 @@ services:
- media-data:/taiga-back/media
# - ./config.py:/taiga-back/settings/config.py
{% if applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'taigaio' %}
{% if applications[application_id].features.oidc and applications[application_id].oidc.flavor == 'taigaio' %}
- {{ docker_compose.directories.config }}taiga-local.py:/taiga-back/settings/local.py:ro
@@ -22,7 +22,7 @@ services:
condition: service_started
taiga-async-rabbitmq:
condition: service_started
{% if applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'taigaio' %}
{% if applications[application_id].features.oidc and applications[application_id].oidc.flavor == 'taigaio' %}
command: >
/bin/sh -c "
@@ -42,7 +42,7 @@ services:
- media-data:/taiga-back/media
# - ./config.py:/taiga-back/settings/config.py
{% if applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'taigaio' %}
{% if applications[application_id].features.oidc and applications[application_id].oidc.flavor == 'taigaio' %}
{% for item in settings_files %}
- {{ docker_compose.directories.config }}taiga-{{ item }}.py:/taiga-back/settings/{{ item }}.py:ro
@@ -57,7 +57,7 @@ services:
condition: service_started
taiga-async-rabbitmq:
condition: service_started
{% if applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'taigaio' %}
{% if applications[application_id].features.oidc and applications[application_id].oidc.flavor == 'taigaio' %}
command: >
/bin/sh -c "

View File

@@ -47,7 +47,7 @@ MAX_AGE = 360
# Taiga's Telemetry - Variable to enable or disable the anonymous telemetry
ENABLE_TELEMETRY = True
{% if applications[application_id].oidc.enabled %}
{% if applications[application_id].features.oidc %}
{% if applications[application_id].oidc.flavor == 'taigaio' %}

View File

@@ -5,10 +5,10 @@ docker_repository_address: "https://github.com/taigaio/taiga-docker"
email_backend: "smtp" ## use an SMTP server or display the emails in the console (either "smtp" or "console")
docker_compose_init: "{{docker_compose.directories.instance}}docker-compose-inits.yml.j2"
taiga_image_backend: >-
{{ 'robrotheram/taiga-back-openid' if applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'robrotheram'
{{ 'robrotheram/taiga-back-openid' if applications[application_id].features.oidc and applications[application_id].oidc.flavor == 'robrotheram'
else 'taigaio/taiga-back' }}
taiga_image_frontend: >-
{{ 'robrotheram/taiga-front-openid' if applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'robrotheram'
{{ 'robrotheram/taiga-front-openid' if applications[application_id].features.oidc and applications[application_id].oidc.flavor == 'robrotheram'
else 'taigaio/taiga-front' }}
taiga_frontend_conf_path: "{{docker_compose.directories.config}}conf.json"

View File

@@ -39,4 +39,8 @@
- name: "Activating OIDC when enabled."
include_tasks: oidc.yml
when: applications[application_id].oidc.enabled | bool
when: applications[application_id].features.oidc | bool
#- name: "Activating WP Discourse when enabled"
# include_tasks: wp_discourse.yml
# when: applications[application_id].wp_discourse.enabled | bool

View File

@@ -0,0 +1,23 @@
---
- name: "Create Discourse API key for WordPress integration"
uri:
url: "https://{{ domains.discourse }}/admin/api/keys"
method: POST
headers:
Content-Type: "application/json"
Api-Key: "{{ applications.discourse.master_api_key }}"
Api-Username: "{{ applications.discourse.master_api_username | default('admin') }}"
body_format: json
body:
key:
description: "WP Discourse Integration"
username: "system"
return_content: true
status_code: 200
register: discourse_api_key_response
when: applications.discourse.master_api_key is defined
- name: "Set fact for vault_discourse_api_key"
set_fact:
vault_discourse_api_key: "{{ discourse_api_key_response.json.key.key }}"
when: discourse_api_key_response is defined and discourse_api_key_response.json.key is defined

View File

@@ -0,0 +1,17 @@
---
- name: "Install WP Discourse plugin"
command: >
docker-compose exec -u www-data -T application
wp plugin install wp-discourse --activate
--path={{ wordpress_docker_html_path }}
args:
chdir: "{{ docker_compose.directories.instance }}"
- name: "Configure WP Discourse settings"
vars:
discourse_settings_json_b64: "{{ discourse_settings | to_json | b64encode }}"
command: >
docker-compose exec -u www-data -T application bash -lc
"wp eval \"update_option('wp_discourse_options', json_decode(base64_decode('{{ discourse_settings_json_b64 }}'), true));\" --path={{ wordpress_docker_html_path }}"
args:
chdir: "{{ docker_compose.directories.instance }}"

View File

@@ -0,0 +1,10 @@
# Defines WP Discourse plugin settings
# @see https://github.com/discourse/wp-discourse
discourse_settings:
publish_discourse_posts: true
discourse_url: "https://{{ domains.discourse }}"
discourse_api_key: "{{ applications.discourse.api_key }}"
discourse_username: "system"
discourse_use_sso: false # You can change this depending on your integration style
discourse_sso_secret: "{{ applications.wordpress.credentials.discourse_sso_secret | default('') }}"

View File

@@ -0,0 +1,2 @@
# Todo
- Implement health check for oauth2-proxy

View File

@@ -1,4 +1,4 @@
{% if landingpage_iframe_enabled | default(applications.get(application_id).get('landingpage_iframe_enabled')) | bool %}
{% if applications.get(application_id, {}).get('features', {}).get('iframe', False) %}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy "frame-ancestors 'self' {{primary_domain}};" always;
{% endif %}

View File

@@ -1,9 +1,9 @@
- name: "Activate Global CSS for {{domain}}"
include_role:
name: nginx-modifier-css
when: applications.get(application_id).get('css_enabled') | bool
when: applications.get(application_id).get('features').get('css') | bool
- name: "Activate Global Matomo Tracking for {{domain}}"
include_role:
name: nginx-modifier-matomo
when: applications.get(application_id).get('matomo_tracking_enabled') | bool
when: applications.get(application_id).get('features').get('matomo') | bool

View File

@@ -2,20 +2,20 @@
sub_filter_once off;
sub_filter_types text/html;
{% set css_enabled_final = applications.get(application_id).get('css_enabled') | bool %}
{% set matomo_tracking_enabled_final = applications.get(application_id).get('matomo_tracking_enabled') | bool %}
{% set features_css_final = applications.get(application_id).get('features').get('css') | bool %}
{% set features_matomo_final = applications.get(application_id).get('features').get('matomo') | bool %}
{% if matomo_tracking_enabled_final | bool %}
{% if features_matomo_final | bool %}
{# Include Global Matomo Tracking #}
{% include 'roles/nginx-modifier-matomo/templates/matomo-tracking.conf.j2' %}
{% endif %}
{% if css_enabled_final | bool or matomo_tracking_enabled_final | bool %}
sub_filter '</head>' '{% if matomo_tracking_enabled_final | bool %}{% include 'roles/nginx-modifier-matomo/templates/script.j2' %}{% endif %}{% if css_enabled_final | bool %}{% include 'roles/nginx-modifier-css/templates/link.j2' %}{% endif %}</head>';
{% if features_css_final | bool or features_matomo_final | bool %}
sub_filter '</head>' '{% if features_matomo_final | bool %}{% include 'roles/nginx-modifier-matomo/templates/script.j2' %}{% endif %}{% if features_css_final | bool %}{% include 'roles/nginx-modifier-css/templates/link.j2' %}{% endif %}</head>';
{% endif %}
{% if css_enabled_final | bool %}
{% if features_css_final | bool %}
{# Include Global CSS Location #}
{% include 'roles/nginx-modifier-css/templates/location.conf.j2' %}
{% endif %}

View File

@@ -30,7 +30,7 @@
uri:
url: "https://{{ domains.matomo }}/index.php"
method: POST
body: "module=API&method=SitesManager.addSite&siteName={{ base_domain }}&urls=https://{{ base_domain }}&token_auth={{ applications.matomo.auth_token }}&format=json"
body: "module=API&method=SitesManager.addSite&siteName={{ base_domain }}&urls=https://{{ base_domain }}&token_auth={{ applications.matomo.credentials.auth_token }}&format=json"
body_format: form-urlencoded
status_code: 200
return_content: yes

View File

@@ -1,2 +1,2 @@
base_domain: "{{ domain | regex_replace('^(?:.*\\.)?(.+\\..+)$', '\\1') }}"
verification_url: "https://{{domains.matomo}}/index.php?module=API&method=SitesManager.getSitesIdFromSiteUrl&url=https://{{base_domain}}&format=json&token_auth={{applications.matomo.auth_token}}"
verification_url: "https://{{domains.matomo}}/index.php?module=API&method=SitesManager.getSitesIdFromSiteUrl&url=https://{{base_domain}}&format=json&token_auth={{applications.matomo.credentials.auth_token}}"