diff --git a/site.yml b/site.yml index 4a721d3cd93f08c74ba1637e413e373563e0d2df..3d9eb969df41f519d8211a90ccec3fc07eca2dad 100644 --- a/site.yml +++ b/site.yml @@ -54,6 +54,12 @@ basedir: "/srv/{{ servicename }}", domain: "verwaltung-git.test-warpzone.de" } + - { + role: testserver/docker_grafana, tags: [ test_grafana, docker_services ], + servicename: "grafana", + basedir: "/srv/{{ servicename }}", + domain: "grafana.test-warpzone.de" + } - { role: testserver/docker_nextcloud, tags: [ test_nextcloud, docker_services ], servicename: "nextcloud", @@ -66,6 +72,18 @@ basedir: "/srv/{{ servicename }}", domain: "tandoor.test-warpzone.de" } + - { + role: testserver/docker_vpnserver, tags: [ test_vpnserver, docker_services ], + servicename: "vpnserver", + basedir: "/srv/{{ servicename }}", + domain: "vpn.test-warpzone.de" + } + - { + role: testserver/docker_wordpress, tags: [ test_wordpress, docker_services ], + servicename: "wordpress", + basedir: "/srv/{{ servicename }}", + domain: "www.test-warpzone.de" + } ################################################## @@ -280,12 +298,6 @@ basedir: /srv/matrix, domain: "matrix.warpzone.ms" } - - { - role: webserver/docker_vpnserver, tags: [ vpnserver, docker_services ], - servicename: "vpnserver", - basedir: /srv/vpnserver, - domain: "vpn.warpzone.ms" - } - { role: webserver/docker_warpapi, tags: [ warpapi, docker_services ], servicename: "warpapi", diff --git a/testserver/docker_wordpress/Documentation.md b/testserver/docker_wordpress/Documentation.md new file mode 100644 index 0000000000000000000000000000000000000000..5ebd4b77d1a7d6d83801fe47a2a98c6552e885a0 --- /dev/null +++ b/testserver/docker_wordpress/Documentation.md @@ -0,0 +1,94 @@ + +# Overview + +* Authentication to Wordpress is only possible with an account in uffd, regular authentication is disabled +* All users with group 'wordpress_access' can access Wordpress with 'Editor' privileges, the user in Wordpress is created on first login +* Users with group 'wordpress_admin' get 'Administrator' privigeges. + +# Setup OIDC Authentication via uffd + +Uffd Reference: https://git.cccv.de/uffd + + +## Setup in Wordpress + +Wordpress Plugin: OpenID Connect Generic Client +https://de.wordpress.org/plugins/daggerhart-openid-connect-generic + +Pluin settings: +* Anmeldetyp: +* Client-ID: wordpress +* Client Secret Key: <secret key> +* OpenID Scope: openid profile email groups +* Endpunkt-URL zur Anmeldung: https://uffd.test-warpzone.de/oauth2/authorize +* Endpunkt-URL zur Benutzerinfo: https://uffd.test-warpzone.de/oauth2/userinfo +* Endpunkt-URL zur Token-Verifizierung: https://uffd.test-warpzone.de/oauth2/token +* Endpunkt-URL zum Sitzungsende: https://uffd.test-warpzone.de/oauth2/logout +* Identitäts-Schlüssel: preferred_username +* Spitznamen-Schlüssel: preferred_username +* Email-Format: {email} +* Anzeigename-Formatierung: {preferred_username} +* Mit Benutzername identifizieren: Ja +* State-Zeitbeschränkung: 180 +* Aktualisierungstoken aktivieren: Ja +* Existierende Benutzer verknüpfen: Ja +* Benutzer erstellen, wenn er nicht existiert: Ja +* Zur ursprünglichen Seite zurückleiten: Nein +* Zur Anmeldeansicht weiterleiten, wenn die Sitzung abgelaufen ist: Ja + +## Setup in uffd + +Create Groups: + +- wordpress_access: General Access to Nextcloud +- wordpress_admin: This Group will be Mapped to the Group admin in Wordpress + +Create a Service / OAuth Client: + +Only Users with goup nextcloud_access can access Nextcloud + +Client-ID: wordpress +Client-Secret: from file nextcloud_oidc_secret on the server +Redirect-URIs: +* https://www.test-warpzone.de/wp-admin/admin-ajax.php?action=openid-connect-authorize + +## Mapping von Rollen in Wordpress + +Wordpress Plugin: WPCode +https://de.wordpress.org/plugins/insert-headers-and-footers/ + +Additional references: +https://github.com/oidc-wp/openid-connect-generic/issues/164 + +Um die Wordpress Berechtigungen auf Basis der Gruppen in uffd zu steuern ist ein zusätzliches Code-Snippet erforderlich. +Dieses Code-Snippet kann am besten mit dem addon 'WPCode' verwaltet werden. +In dem Plugin muss das folgenden neues PHP-Snippet erstellt und aktiviert werden. + +Benutzer, mit der Gruppe 'wordpress_admin' in uddf erhalten Administrator-Berechtigungen. +Alle anderen Benutzer erhalten Editor-Berechtigungen. + +``` +add_action('openid-connect-generic-update-user-using-current-claim', function( $user, $user_claim) { + + // Based on some data in the user_claim, modify the user. + foreach($user_claim as $key => $value) { + error_log('Openid Role mapping: User claim: ' . $key . ", Value: " . $value); + } + + if ( array_key_exists( 'groups', $user_claim ) ) { + + error_log('Openid Role mapping: Groups: ' . implode(',',$user_claim['groups'])); + + if ( in_array('wordpress_admin', $user_claim['groups'] )) { + + error_log('Openid Role mapping: Set role: Administrator'); + $user->set_role( 'administrator' ); + } + else { + + error_log('Openid Role mapping: Set role: Editor'); + $user->set_role( 'editor' ); + } + } +}, 10, 2); +``` diff --git a/testserver/docker_wordpress/tasks/main.yml b/testserver/docker_wordpress/tasks/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..46107a11a4cd50f760f46ecc4e411acba709d288 --- /dev/null +++ b/testserver/docker_wordpress/tasks/main.yml @@ -0,0 +1,39 @@ +--- + +- include_tasks: ../functions/get_secret.yml + with_items: + - { path: "/srv/shared/noreply_email_pass", length: -1 } + - { path: "{{ basedir }}/mysql_root_pass", length: 24 } + - { path: "{{ basedir }}/mysql_user_pass", length: 12 } + - { path: "{{ basedir }}/wordpress_admin_pass", length: 24 } + - { path: "{{ basedir }}/wordpress_client_secret", length: 32 } + +- name: create folder struct for wordpress + file: + path: "{{ item }}" + state: "directory" + owner: www-data + group: www-data + with_items: + - "{{ basedir }}/" + - "{{ basedir }}/db/" + - "{{ basedir }}/config" + - "{{ basedir }}/data/" + - "{{ basedir }}/data/wp-content/" + - "{{ basedir }}/data/wp-content/plugins/" + - "{{ basedir }}/data/wp-content/plugins/wz-status/" + +- name: create config file + template: + src: "{{ item }}" + dest: "{{ basedir }}/{{ item }}" + with_items: + - Dockerfile + - docker-compose.yml + - config/uploads.ini + - data/wp-content/plugins/wz-status/wz-status.php + +- name: start wordpress docker + community.docker.docker_compose_v2: + project_src: "{{ basedir }}" + state: present diff --git a/testserver/docker_wordpress/templates/Dockerfile b/testserver/docker_wordpress/templates/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..1c41da02f4c43761b8e7f8e4639d7314a7390b4a --- /dev/null +++ b/testserver/docker_wordpress/templates/Dockerfile @@ -0,0 +1,10 @@ +FROM wordpress:6.4.2-apache + +# install the PHP extensions we need +RUN set -x \ + && apt-get update \ + && apt-get install -y libldap2-dev \ + && rm -rf /var/lib/apt/lists/* \ + && docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ \ + && docker-php-ext-install ldap \ + && apt-get purge -y --auto-remove libldap2-dev diff --git a/testserver/docker_wordpress/templates/config/uploads.ini b/testserver/docker_wordpress/templates/config/uploads.ini new file mode 100644 index 0000000000000000000000000000000000000000..c32c80ec4475ac54fb2ce2c7deb03677be062942 --- /dev/null +++ b/testserver/docker_wordpress/templates/config/uploads.ini @@ -0,0 +1,6 @@ + +file_uploads = On +memory_limit = 64M +upload_max_filesize = 64M +post_max_size = 64M +max_execution_time = 600 diff --git a/testserver/docker_wordpress/templates/data/wp-content/plugins/wz-status/wz-status.php b/testserver/docker_wordpress/templates/data/wp-content/plugins/wz-status/wz-status.php new file mode 100644 index 0000000000000000000000000000000000000000..36b3bf0a09affb3d2a6345d314291b8d84c4659d --- /dev/null +++ b/testserver/docker_wordpress/templates/data/wp-content/plugins/wz-status/wz-status.php @@ -0,0 +1,152 @@ +<?php +/* +Plugin Name: WZ Status +Plugin URI: http://www.warpzone.ms +Description: This plugin adds a custom widget. +Version: 1.0 +Author: Christian <void> Elberfeld +Author URI: http://www.warpzone.ms +License: GPL2 +Original Source: https://github.com/wpexplorer/my-widget-plugin +*/ + +// The widget class +class WZ_Status_Widget extends WP_Widget { + + // Main constructor + public function __construct() { + parent::__construct( + 'wz_status_widget', + __( 'WZ Status Widget', 'text_domain' ), + array( + 'customize_selective_refresh' => true, + ) + ); + } + + // The widget form (for the backend ) + public function form( $instance ) { + + // Set widget defaults + $defaults = array( + 'title' => '', + 'api_url' => '', + ); + + // Parse current settings with defaults + extract( wp_parse_args( ( array ) $instance, $defaults ) ); ?> + + <?php // Widget Title ?> + <p> + <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php _e( 'Widget Title', 'text_domain' ); ?></label> + <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" /> + </p> + + <?php // Api Url ?> + <p> + <label for="<?php echo esc_attr( $this->get_field_id( 'api_url' ) ); ?>"><?php _e( 'Api Url:', 'api_url' ); ?></label> + <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'api_url' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'api_url' ) ); ?>" type="text" value="<?php echo esc_attr( $text ); ?>" /> + </p> + + + <?php } + + // Update widget settings + public function update( $new_instance, $old_instance ) { + $instance = $old_instance; + $instance['title'] = isset( $new_instance['title'] ) ? wp_strip_all_tags( $new_instance['title'] ) : ''; + $instance['api_url'] = isset( $new_instance['api_url'] ) ? wp_strip_all_tags( $new_instance['api_url'] ) : ''; + return $instance; + } + + // Display the widget + public function widget( $args, $instance ) { + + extract( $args ); + + // Check the widget options + $title = isset( $instance['title'] ) ? apply_filters( 'widget_title', $instance['title'] ) : ''; + $api_url = isset( $instance['api_url'] ) ? $instance['api_url'] : ''; + + $zone_status = "UNBEKANNT"; + $zone_status_text = "Unbekannt"; + $zone_status_color = "#000000"; + + // WordPress core before_widget hook (always include ) + echo $before_widget; + + // Display the widget + echo '<div class="widget-text wp_widget_plugin_box">'; + + // Display widget title if defined + if ( $title ) { + echo $before_title . $title . $after_title; + } + + + // Zone Status abrufen + + $curl = curl_init(); + + curl_setopt_array($curl, array( + CURLOPT_URL => "https://api.warpzone.ms/statuswidget", + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_ENCODING => "", + CURLOPT_MAXREDIRS => 3, + CURLOPT_TIMEOUT => 5, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => "GET" + )); + + $response = curl_exec($curl); + $err = curl_error($curl); + + curl_close($curl); + + if ($err) { + + $zone_status = $err; + + } else { + + $responseObj = json_decode($response,true); + $zone_status = $responseObj['zone_door_status']; + + if ($zone_status == "OPEN") { + + $zone_status_text = "Offen"; + $zone_status_color = "#00cc00"; + } + + if ($zone_status == "CLOSED") { + + $zone_status_text = "Geschlossen"; + $zone_status_color = "#cc0000"; + } + + } + + + // Anzeige Status im Widget + echo "<span style='font-weight: bold; color:" . $zone_status_color . ";'>" . $zone_status_text . "</span>"; + + // Status mit in die Menueleiste fuer Mobilgeraete + echo "<script type='text/javascript'>jQuery(document).ready(function() { jQuery('#mainnav-toggle').text('MENU | Status: " . $zone_status_text . "'); });</script>"; + + + echo '</div>'; + + // WordPress core after_widget hook (always include ) + echo $after_widget; + + } + +} + +// Register the widget +function my_register_wz_status_widget() { + register_widget( 'WZ_Status_Widget' ); +} +add_action( 'widgets_init', 'my_register_wz_status_widget' ); + diff --git a/testserver/docker_wordpress/templates/docker-compose.yml b/testserver/docker_wordpress/templates/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..e0c093ac5e5a468273a10673e28e5edfa8747db2 --- /dev/null +++ b/testserver/docker_wordpress/templates/docker-compose.yml @@ -0,0 +1,40 @@ +services: + + db: + + image: mariadb:11 + restart: always + volumes: + - /srv/wordpress/db/:/var/lib/mysql + environment: + MYSQL_ROOT_PASSWORD: "{{ mysql_root_pass }}" + MYSQL_PASSWORD: "{{ mysql_user_pass }}" + MYSQL_DATABASE: wordpress + MYSQL_USER: wordpress + networks: + - default + + app: + # values set in configuration: noreply_email_user - noreply_email_pass - smtp_host - smtp_port + build: . + restart: always + volumes: + - /srv/wordpress/config/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini + - /srv/wordpress/data:/var/www/html + environment: + WORDPRESS_DB_HOST: db + WORDPRESS_DB_USER: wordpress + WORDPRESS_DB_PASSWORD: "{{ mysql_user_pass }}" + labels: + - com.centurylinklabs.watchtower.enable=false + - traefik.enable=true + - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`) + - traefik.http.routers.{{ servicename }}.entrypoints=websecure + - traefik.http.services.{{ servicename }}.loadbalancer.server.port=80 + networks: + - default + - web + +networks: + web: + external: true diff --git a/webserver/docker_wordpress/tasks/main.yml b/webserver/docker_wordpress/tasks/main.yml index 0f207950a08fce9bd0b9232f3dd7500b250c343b..995f4bceff5c96c35e36a1fd8b9ae6febded91de 100644 --- a/webserver/docker_wordpress/tasks/main.yml +++ b/webserver/docker_wordpress/tasks/main.yml @@ -2,9 +2,9 @@ - include_tasks: ../functions/get_secret.yml with_items: - - { path: /srv/shared/noreply_email_pass, length: -1 } - - { path: /srv/wordpress/mysql_root_pass, length: 24 } - - { path: /srv/wordpress/mysql_user_pass, length: 12 } + - { path: "/srv/shared/noreply_email_pass", length: -1 } + - { path: "{{ basedir }}/mysql_root_pass", length: 24 } + - { path: "{{ basedir }}/mysql_user_pass", length: 12 } - name: create folder struct for wordpress file: @@ -13,15 +13,18 @@ owner: www-data group: www-data with_items: - - "/srv/wordpress/" - - "/srv/wordpress/config" - - "/srv/wordpress/data/" - - "/srv/wordpress/db/" + - "{{ basedir }}/" + - "{{ basedir }}/db/" + - "{{ basedir }}/config" + - "{{ basedir }}/data/" + - "{{ basedir }}/data/wp-content/" + - "{{ basedir }}/data/wp-content/plugins/" + - "{{ basedir }}/data/wp-content/plugins/wz-status/" - name: create config file template: src: "{{ item }}" - dest: "/srv/wordpress/{{ item }}" + dest: "{{ basedir }}/{{ item }}" with_items: - Dockerfile - docker-compose.yml @@ -30,5 +33,5 @@ - name: start wordpress docker community.docker.docker_compose_v2: - project_src: /srv/wordpress/ + project_src: "{{ basedir }}" state: present