Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • infrastruktur/ansible-warpzone
  • specki/ansible-warpzone
2 results
Show changes
Showing
with 636 additions and 569 deletions
<?php
/**
* Default settings for the oauthgeneric plugin
*/
$conf['key'] = 'dokuwiki';
$conf['secret'] = '{{ oauth_secret }}';
$conf['authurl'] = '{{ oauth_global.authorize_url }}';
$conf['tokenurl'] = '{{ oauth_global.token_url }}';
$conf['userurl'] = '{{ oauth_global.userinfo_url }}';
$conf['authmethod'] = '1';
$conf['scopes'] = 'email, openid, profile, groups';
$conf['needs-state'] = 0;
$conf['json-user'] = 'prefered_username';
$conf['json-name'] = 'name';
$conf['json-mail'] = 'email';
$conf['json-grps'] = 'groups';
$conf['label'] = 'uffd';
$conf['color'] = '#ff3d00';
\ No newline at end of file
FROM debian:bookworm-slim
# Set environment variables
ENV DEBIAN_FRONTEND=noninteractive
# Install necessary dependencies and configure custom repository
RUN apt-get update \
&& apt-get install -y --no-install-recommends wget gnupg ca-certificates \
&& wget -O- "https://packages.cccv.de/docs/cccv-archive-key.gpg" | gpg --dearmor -o /etc/apt/trusted.gpg.d/cccv-archive-key.gpg \
&& echo "deb https://packages.cccv.de/uffd bookworm main" > /etc/apt/sources.list.d/custom.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends uffd-ldapd ldap-utils \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
USER 999
EXPOSE 389/tcp
# Set default command
CMD ["/usr/sbin/uffd-ldapd","--socket-address","0.0.0.0:389"]
# Get all LDAP Entries
# ldapsearch -x -H ldap://127.0.0.1 -D "cn=service,ou=system,{{ oidc_global.ldap_base_dn }}" -w "{{ ldap_bind_pw }}" -b "ou=users,{{ oidc_global.ldap_base_dn }}" "(objectClass=*)"
......@@ -179,3 +179,6 @@ DEFAULT_SPAM_THRESHOLD=80
# API token required for authenticating to the RESTful API.
# This is a mandatory setting for using the RESTful API.
API_TOKEN={{ mailu_api_token }}
#Advanced Vector Extensions
LD_PRELOAD=/usr/lib/libhardened_malloc.so
\ No newline at end of file
......@@ -3,7 +3,12 @@
- include_tasks: ../functions/get_secret.yml
with_items:
- { path: /srv/shared/noreply_email_pass, length: -1 }
- { path: /srv/ldap/secret/ldap_readonly_pass, length: -1 }
- { path: /srv/matrix/uffd_api_secret, length: 32 }
- { path: /srv/matrix/ldap_bind_pw, length: 32 }
- { path: /srv/matrix/matrix_macaroon_secret_key, length: 32 }
- { path: /srv/matrix/matrix_registration_shared_secret, length: 32 }
- { path: /srv/matrix/matrix_form_secret, length: 32 }
- { path: /srv/matrix/matrix_oidc_secret, length: 32 }
- { path: /srv/matrix/postgres_user_pass, length: 24 }
- { path: /srv/matrix/admin_access_token, length: -1 } # Get in Element fo an Admin User: Settings > Help > Advanced
......@@ -16,8 +21,6 @@
group: www-data
with_items:
- "/srv/matrix/"
- "/srv/matrix/ma1sd-config/"
- "/srv/matrix/ma1sd-data/"
- "/srv/matrix/synapse-data/"
......@@ -29,6 +32,7 @@
group: "999"
with_items:
- "/srv/matrix/db/"
- "/srv/matrix/uffd-ldapd/"
- name: Konfig-Dateien erstellen
......@@ -37,10 +41,9 @@
dest: "/srv/matrix/{{ item }}"
with_items:
- docker-compose.yml
- rest_auth_provider.py
- ma1sd-config/ma1sd.yaml
- synapse-data/homeserver.log.config
- synapse-data/homeserver.yaml
- uffd-ldapd/Dockerfile
register: configs
......
the rest-auth_provider is from https://githubcom/ma1uta/matrix-synapse-rest-password-provider/
Funktionierende oidc-Konfiguration mit authentik
- https://www.youtube.com/watch?v=MwOh4NvPdtQ
- https://github.com/matrix-org/tutorial-oidc-playground
......@@ -23,6 +23,19 @@ services:
networks:
- default
ldap:
build: uffd-ldapd/
restart: always
environment:
SERVER_API_URL: "{{ oidc_global.provider_url }}"
SERVER_API_USER: "matrixldap"
SERVER_API_SECRET: "{{ uffd_api_secret }}"
SERVER_BASE_DN: "{{ oidc_global.ldap_base_dn }}"
SERVER_BIND_PASSWORD: "{{ ldap_bind_pw}}"
networks:
- default
synapse:
image: matrixdotorg/synapse:latest
......@@ -31,11 +44,9 @@ services:
cpuset: "0"
depends_on:
- db
- ma1sd
- ldap
volumes:
- /srv/matrix/synapse-data/:/data
# Python version can be found in the dockerfile: https://github.com/matrix-org/synapse/blob/develop/docker/Dockerfile check for tag to get the correct version
- /srv/matrix/rest_auth_provider.py:/usr/local/lib/python3.11/site-packages/rest_auth_provider.py
environment:
SYNAPSE_CONFIG_PATH: "/data/homeserver.yaml"
TZ: "Europe/Berlin"
......@@ -53,23 +64,6 @@ services:
- default
- web
ma1sd:
image: ma1uta/ma1sd:2.5.0
restart: always
volumes:
- /srv/matrix/ma1sd-config/:/etc/ma1sd
- /srv/matrix/ma1sd-data/:/var/ma1sd
labels:
- com.centurylinklabs.watchtower.enable=false
- traefik.enable=true
- traefik.http.routers.{{ servicename }}-ma1sd.rule=((Host(`{{ domain }}`) && PathPrefix(`/_matrix/client/r0/login`)) || (Host(`{{ domain }}`) && PathPrefix(`/_matrix/identity`)))
- traefik.http.routers.{{ servicename }}-ma1sd.entrypoints=websecure
- traefik.http.services.{{ servicename }}-ma1sd.loadbalancer.server.port=8090
networks:
- default
- web
purgemediacache:
......
#######################
# Matrix config items #
#######################
# Matrix domain, same as the domain configure in your Homeserver configuration.
# NOTE: in Synapse Homeserver, the Matrix domain is defined as 'server_name' in configuration file.
#
# This is used to build the various identifiers in all the features.
#
# If the hostname of the public URL used to reach your Matrix services is different from your Matrix domain,
# per example matrix.domain.tld vs domain.tld, then use the server.name configuration option.
# See the "Configure" section of the Getting Started guide for more info.
#
matrix:
domain: 'matrix.warpzone.ms'
v1: true # deprecated
v2: true # MSC2140 API v2. Riot require enabled V2 API.
################
# Signing keys #
################
# Absolute path for the Identity Server signing keys database.
# /!\ THIS MUST **NOT** BE YOUR HOMESERVER KEYS FILE /!\
# If this path does not exist, it will be auto-generated.
#
# During testing, /var/tmp/ma1sd/keys is a possible value
# For production, recommended location shall be one of the following:
# - /var/lib/ma1sd/keys
# - /var/opt/ma1sd/keys
# - /var/local/ma1sd/keys
#
key:
path: '/var/ma1sd/keys'
# Path to the SQLite DB file for ma1sd internal storage
# /!\ THIS MUST **NOT** BE YOUR HOMESERVER DATABASE /!\
#
# Examples:
# - /var/opt/ma1sd/store.db
# - /var/local/ma1sd/store.db
# - /var/lib/ma1sd/store.db
#
storage:
# backend: sqlite # or postgresql
provider:
sqlite:
database: '/var/ma1sd/store.db'
# postgresql:
# # Wrap all string values with quotes to avoid yaml parsing mistakes
# database: '//localhost/ma1sd' # or full variant //192.168.1.100:5432/ma1sd_database
# username: 'ma1sd_user'
# password: 'ma1sd_password'
#
# # Pool configuration for postgresql backend.
# #######
# # Enable or disable pooling
# pool: false
#
# #######
# # Check database connection before get from pool
# testBeforeGetFromPool: false # or true
#
# #######
# # There is an internal thread which checks each of the database connections as a keep-alive mechanism. This set the
# # number of milliseconds it sleeps between checks -- default is 30000. To disable the checking thread, set this to
# # 0 before you start using the connection source.
# checkConnectionsEveryMillis: 30000
#
# #######
# # Set the number of connections that can be unused in the available list.
# maxConnectionsFree: 5
#
# #######
# # Set the number of milliseconds that a connection can stay open before being closed. Set to 9223372036854775807 to have
# # the connections never expire.
# maxConnectionAgeMillis: 3600000
###################
# Identity Stores #
###################
# If you are using synapse standalone and do not have an Identity store,
# see https://github.com/ma1uta/ma1sd/blob/master/docs/stores/synapse.md#synapse-identity-store
#
# If you would like to integrate with your AD/Samba/LDAP server,
# see https://github.com/ma1uta/ma1sd/blob/master/docs/stores/ldap.md
#
# For any other Identity store, or to simply discover them,
# see https://github.com/ma1uta/ma1sd/blob/master/docs/stores/README.md
ldap:
enabled: true
connection:
host: '{{ ldap_ip_ext }}'
port: 389
bindDn: '{{ ldap_readonly_bind_dn }}'
bindPassword: '{{ ldap_readonly_pass }}'
baseDNs:
- '{{ ldap_base_dn }}'
filter: '(&(objectClass=inetOrgPerson)(memberof=CN=active,OU=groups,DC=warpzone,DC=ms))'
attribute:
uid:
type: 'uid'
value: 'uid'
name: 'uid'
threepid:
email:
- 'mail'
msisdn:
- 'phone'
#################################################
# Notifications for invites/addition to profile #
#################################################
# This is mandatory to deal with anything e-mail related.
#
# For an introduction to sessions, invites and 3PIDs in general,
# see https://github.com/ma1uta/ma1sd/blob/master/docs/threepids/session/session.md#3pid-sessions
#
# If you would like to change the content of the notifications,
# see https://github.com/ma1uta/ma1sd/blob/master/docs/threepids/notification/template-generator.md
#
#### E-mail connector
threepid:
medium:
email:
identity:
# The e-mail to send as.
from: "matrix-identity@warpzone.ms"
connectors:
smtp:
# SMTP host
host: "{{ smtp_host }}"
# TLS mode for the connection
# Possible values:
# 0 Disable any kind of TLS entirely
# 1 Enable STARTLS if supported by server (default)
# 2 Force STARTLS and fail if not available
# 3 Use full TLS/SSL instead of STARTLS
#
tls: 1
# SMTP port
# Be sure to adapt depending on your TLS choice, if changed from default
port: "{{ smtp_port }}"
# Login for SMTP
login: "{{ noreply_email_user }}"
# Password for the account
password: "{{ noreply_email_pass }}"
#### MSC2134 (hash lookup)
#hashing:
# enabled: false # enable or disable the hash lookup MSC2140 (default is false)
# pepperLength: 20 # length of the pepper value (default is 20)
# rotationPolicy: per_requests # or `per_seconds` how often the hashes will be updating
# hashStorageType: sql # or `in_memory` where the hashes will be stored
# algorithms:
# - none # the same as v1 bulk lookup
# - sha256 # hash the 3PID and pepper.
# delay: 2m # how often hashes will be updated if rotation policy = per_seconds (default is 10s)
# requests: 10 # how many lookup requests will be performed before updating hashes if rotation policy = per_requests (default is 10)
### hash lookup for synapseSql provider.
# synapseSql:
# lookup:
# query: 'select user_id as mxid, medium, address from user_threepid_id_server' # query for retrive 3PIDs for hashes.
# legacyRoomNames: false # use the old query to get room names.
### hash lookup for ldap provider (with example of the ldap configuration)
# ldap:
# enabled: true
# lookup: true # hash lookup
# activeDirectory: false
# defaultDomain: ''
# connection:
# host: 'ldap.domain.tld'
# port: 389
# bindDn: 'cn=admin,dc=domain,dc=tld'
# bindPassword: 'Secret'
# baseDNs:
# - 'dc=domain,dc=tld'
# attribute:
# uid:
# type: 'uid' # or mxid
# value: 'cn'
# name: 'displayName'
# identity:
# filter: '(objectClass=inetOrgPerson)'
#### MSC2140 (Terms)
#policy:
# policies:
# term_name: # term name
# version: 1.0 # version
# terms:
# en: # lang
# name: term name en # localized name
# url: https://ma1sd.host.tld/term_en.html # localized url
# fe: # lang
# name: term name fr # localized name
# url: https://ma1sd.host.tld/term_fr.html # localized url
# regexp:
# - '/_matrix/identity/v2/account.*'
# - '/_matrix/identity/v2/hash_details'
# - '/_matrix/identity/v2/lookup'
#
# logging:
# root: error # default level for all loggers (apps and thirdparty libraries)
# app: info # log level only for the ma1sd
# requests: false # or true to dump full requests and responses
dns:
overwrite:
homeserver:
client:
- name: 'matrix.warpzone.ms'
value: 'http://synapse:8008'
session:
policy:
validation:
enabled: false
# -*- coding: utf-8 -*-
#
# REST endpoint Authentication module for Matrix synapse
# Copyright (C) 2017 Kamax Sarl
#
# https://www.kamax.io/
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import logging
from twisted.internet import defer
import requests
import json
import time
logger = logging.getLogger(__name__)
class RestAuthProvider(object):
def __init__(self, config, account_handler):
self.account_handler = account_handler
if not config.endpoint:
raise RuntimeError('Missing endpoint config')
self.endpoint = config.endpoint
self.regLower = config.regLower
self.config = config
logger.info('Endpoint: %s', self.endpoint)
logger.info('Enforce lowercase username during registration: %s', self.regLower)
@defer.inlineCallbacks
def check_password(self, user_id, password):
logger.info("Got password check for " + user_id)
data = {'user': {'id': user_id, 'password': password}}
r = requests.post(self.endpoint + '/_matrix-internal/identity/v1/check_credentials', json=data)
r.raise_for_status()
r = r.json()
if not r["auth"]:
reason = "Invalid JSON data returned from REST endpoint"
logger.warning(reason)
raise RuntimeError(reason)
auth = r["auth"]
if not auth["success"]:
logger.info("User not authenticated")
defer.returnValue(False)
localpart = user_id.split(":", 1)[0][1:]
logger.info("User %s authenticated", user_id)
registration = False
if not (yield self.account_handler.check_user_exists(user_id)):
logger.info("User %s does not exist yet, creating...", user_id)
if localpart != localpart.lower() and self.regLower:
logger.info('User %s was cannot be created due to username lowercase policy', localpart)
defer.returnValue(False)
user_id, access_token = (yield self.account_handler.register(localpart=localpart))
registration = True
logger.info("Registration based on REST data was successful for %s", user_id)
else:
logger.info("User %s already exists, registration skipped", user_id)
if auth["profile"]:
logger.info("Handling profile data")
profile = auth["profile"]
# fixme: temporary fix
try:
store = yield self.account_handler._hs.get_profile_handler().store # for synapse >= 1.9.0
except AttributeError:
store = yield self.account_handler.hs.get_profile_handler().store # for synapse < 1.9.0
if "display_name" in profile and ((registration and self.config.setNameOnRegister) or (self.config.setNameOnLogin)):
display_name = profile["display_name"]
logger.info("Setting display name to '%s' based on profile data", display_name)
yield store.set_profile_displayname(localpart, display_name)
else:
logger.info("Display name was not set because it was not given or policy restricted it")
if (self.config.updateThreepid):
if "three_pids" in profile:
logger.info("Handling 3PIDs")
external_3pids = []
for threepid in profile["three_pids"]:
medium = threepid["medium"].lower()
address = threepid["address"].lower()
external_3pids.append({"medium": medium, "address": address})
logger.info("Looking for 3PID %s:%s in user profile", medium, address)
validated_at = time_msec()
if not (yield store.get_user_id_by_threepid(medium, address)):
logger.info("3PID is not present, adding")
yield store.user_add_threepid(
user_id,
medium,
address,
validated_at,
validated_at
)
else:
logger.info("3PID is present, skipping")
if (self.config.replaceThreepid):
for threepid in (yield store.user_get_threepids(user_id)):
medium = threepid["medium"].lower()
address = threepid["address"].lower()
if {"medium": medium, "address": address} not in external_3pids:
logger.info("3PID is not present in external datastore, deleting")
yield store.user_delete_threepid(
user_id,
medium,
address
)
else:
logger.info("3PIDs were not updated due to policy")
else:
logger.info("No profile data")
defer.returnValue(True)
@staticmethod
def parse_config(config):
# verify config sanity
_require_keys(config, ["endpoint"])
class _RestConfig(object):
endpoint = ''
regLower = True
setNameOnRegister = True
setNameOnLogin = False
updateThreepid = True
replaceThreepid = False
rest_config = _RestConfig()
rest_config.endpoint = config["endpoint"]
try:
rest_config.regLower = config['policy']['registration']['username']['enforceLowercase']
except TypeError:
# we don't care
pass
except KeyError:
# we don't care
pass
try:
rest_config.setNameOnRegister = config['policy']['registration']['profile']['name']
except TypeError:
# we don't care
pass
except KeyError:
# we don't care
pass
try:
rest_config.setNameOnLogin = config['policy']['login']['profile']['name']
except TypeError:
# we don't care
pass
except KeyError:
# we don't care
pass
try:
rest_config.updateThreepid = config['policy']['all']['threepid']['update']
except TypeError:
# we don't care
pass
except KeyError:
# we don't care
pass
try:
rest_config.replaceThreepid = config['policy']['all']['threepid']['replace']
except TypeError:
# we don't care
pass
except KeyError:
# we don't care
pass
return rest_config
def _require_keys(config, required):
missing = [key for key in required if key not in config]
if missing:
raise Exception(
"REST Auth enabled but missing required config values: {}".format(
", ".join(missing)
)
)
def time_msec():
"""Get the current timestamp in milliseconds
"""
return int(time.time() * 1000)
......@@ -5,6 +5,9 @@ use_presence: false
allow_public_rooms_without_auth: false
allow_public_rooms_over_federation: true
forget_rooms_on_leave: true
macaroon_secret_key: "{{ matrix_macaroon_secret_key }}"
registration_shared_secret: "{{ matrix_registration_shared_secret }}"
form_secret: "{{ matrix_form_secret}}"
listeners:
- port: 8448
......@@ -62,26 +65,62 @@ thumbnail_sizes:
url_preview_enabled: true
url_preview_ip_range_blacklist:
- '127.0.0.0/8'
- '10.0.0.0/8'
- '172.16.0.0/12'
- '192.168.0.0/16'
- '100.64.0.0/10'
- '192.0.0.0/24'
- '169.254.0.0/16'
- '198.18.0.0/15'
- '192.0.2.0/24'
- '198.51.100.0/24'
- '203.0.113.0/24'
- '224.0.0.0/4'
- '::1/128'
- 'fe80::/10'
- 'fc00::/7'
- '127.0.0.0/8'
- '10.0.0.0/8'
- '172.16.0.0/12'
- '192.168.0.0/16'
- '100.64.0.0/10'
- '192.0.0.0/24'
- '169.254.0.0/16'
- '198.18.0.0/15'
- '192.0.2.0/24'
- '198.51.100.0/24'
- '203.0.113.0/24'
- '224.0.0.0/4'
- '::1/128'
- 'fe80::/10'
- 'fc00::/7'
max_spider_size: 10M
enable_registration: false
default_identity_server: "{{ matrix.identity_server }}"
password_config:
enabled: true
# OIDC Single Sign-On with uffd
oidc_providers:
- idp_id: "uffd"
idp_name: "warpzone SSO (uffd)"
discover: true
enable_registration: true
allow_existing_users: true
user_profile_method: "userinfo_endpoint"
issuer: "{{ oidc_global.provider_url }}"
client_id: "matrix"
client_secret: "{{ matrix_oidc_secret }}"
scopes:
- "openid"
- "profile"
- "email"
user_mapping_provider:
config:
localpart_template: "{% raw %}{{ user.preferred_username }}{% endraw %}"
display_name_template: "{% raw %}{{ user.name }}{% endraw %}"
email_template: "{% raw %}{{ user.email }}{% endraw %}"
# Password login with uffd-ldapd
modules:
- module: "ldap_auth_provider.LdapAuthProviderModule"
config:
enabled: true
uri: "ldap://ldap:389"
start_tls: false
base: "ou=users,{{ oidc_global.ldap_base_dn }}"
attributes:
uid: "uid"
mail: "mail"
name: "displayName"
auto_join_rooms:
- "#warpzone:{{ matrix.domain }}"
......@@ -104,11 +143,6 @@ email:
enable_notifs: true
notif_for_new_users: False
password_providers:
- module: "rest_auth_provider.RestAuthProvider"
config:
endpoint: "http://ma1sd:8090"
encryption_enabled_by_default_for_room_type: invite
enable_group_creation: false
......
FROM debian:bookworm-slim
# Set environment variables
ENV DEBIAN_FRONTEND=noninteractive
# Install necessary dependencies and configure custom repository
RUN apt-get update \
&& apt-get install -y --no-install-recommends wget gnupg ca-certificates \
&& wget -O- "https://packages.cccv.de/docs/cccv-archive-key.gpg" | gpg --dearmor -o /etc/apt/trusted.gpg.d/cccv-archive-key.gpg \
&& echo "deb https://packages.cccv.de/uffd bookworm main" > /etc/apt/sources.list.d/custom.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends uffd-ldapd ldap-utils \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
USER 999
EXPOSE 389/tcp
# Set default command
CMD ["/usr/sbin/uffd-ldapd","--socket-address","0.0.0.0:389"]
# Get all LDAP Entries
# ldapsearch -x -H ldap://127.0.0.1 -D "cn=service,ou=system,{{ oidc_global.ldap_base_dn }}" -w "{{ ldap_bind_pw }}" -b "ou=users,{{ oidc_global.ldap_base_dn }}" "(objectClass=*)"
......@@ -14,12 +14,12 @@ ACL_ACCESS_GROUP="uffd_access"
# Members can create invite links for signup
ACL_SIGNUP_GROUP="uffd_signup"
MAIL_SERVER='mail.test-warpzone.de'
MAIL_SERVER='mail.warpzone.ms'
MAIL_PORT=587
MAIL_USERNAME='noreply-uffd@test-warpzone.de'
MAIL_USERNAME='uffd-test@warpzone.ms'
MAIL_PASSWORD='{{ uffd_mail_pass }}'
MAIL_USE_STARTTLS=True
MAIL_FROM_ADDRESS='noreply-uffd@test-warpzone.de'
MAIL_FROM_ADDRESS='uffd-test@warpzone.ms'
# Do not enable this on a public service! There is no spam protection implemented at the moment.
SELF_SIGNUP=False
......@@ -110,7 +110,7 @@ SITE_TITLE='uffd @ test-warpzone.de'
# Name and contact mail address are displayed to users in a few places (plain text only!)
ORGANISATION_NAME='test-warpzone.de'
ORGANISATION_CONTACT='uffd@test-warpzone.de'
ORGANISATION_CONTACT='uffd-test@warpzone.ms'
# Optional text included in account registration mails (plain text only!)
WELCOME_TEXT='See https://docs.example.com/ for further information.'
......
......@@ -68,27 +68,31 @@ Benutzer, mit der Gruppe 'wordpress_admin' in uddf erhalten Administrator-Berech
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' );
}
add_action('openid-connect-generic-update-user-using-current-claim', function($user, $user_claim) {
// Log all user claims safely
foreach($user_claim as $key => $value) {
$valueToLog = is_array($value) ? json_encode($value) : $value;
error_log('Openid Role mapping: User claim: ' . $key . ', Value: ' . $valueToLog);
}
if (array_key_exists('groups', $user_claim)) {
// Ensure groups is an array before working with it
if (is_array($user_claim['groups'])) {
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');
}
} else {
// If groups is not an array, log its actual format
error_log('Openid Role mapping: Groups is not an array: ' . gettype($user_claim['groups']));
error_log('Openid Role mapping: Groups value: ' . json_encode($user_claim['groups']));
}
}
}, 10, 2);
```
......@@ -3,8 +3,21 @@ import datetime
from email.message import EmailMessage
from email.utils import formatdate
import requests
import time
import os
def do_work():
def wait_until_unlocked():
# Wait for locks to be released
# If you don't do this and edit DokuWiki pages, others may overwrite what you do
locked = True
while locked:
locked = os.path.isfile("/srv/dokuwiki/data/data/locks/e0bc4d991c71e981423bfefd6d257985.lock")
# Avoid busy loop
if locked:
time.sleep(5)
def get_topics():
with open("/srv/dokuwiki/data/data/pages/intern/diskussionsthemen.txt") as fp:
raw = fp.read().split('\n')
......@@ -13,12 +26,12 @@ def do_work():
lastline = 0
for index, line in enumerate(raw):
# Start marker
if "====== 1." in line:
if "====== 1." in line and not "1.5" in line:
firstline = index + 1
continue
# End marker
if "====== 2." in line:
if "====== 2." in line or "====== 1.5" in line:
lastline = index
break
......@@ -27,51 +40,84 @@ def do_work():
for extracted in raw[firstline:lastline]:
if extracted != '':
topics.append(extracted)
return topics
# There are no topics - just exit
if (len(topics) == 0):
return True
def send_mail(topics, date):
# mail template
mail = f"""
Liebe Zonies,
es gibt wieder Themen die im Plenum besprochen werden sollen. Der nächste
Reguläre Termin ist am nächsten Dienstag ({str(date)}) um 20:00.
Im Wiki (https://wiki.warpzone.ms/intern:diskussionsthemen#diskussionsthemen_naechstes_plenum_automatische_einladung)
stehen folgende Themen:
# calculate date of next tuesday
d = datetime.date.today()
while d.strftime('%a') != 'Tue':
d += datetime.timedelta(1)
{chr(10).join(topics)}
# mail template
mail = f"""
Liebe Zonies,
es gibt wieder Themen die im Plenum besprochen werden sollen. Der nächste
Reguläre Termin ist am nächsten Dienstag ({str(d)}) um 20:00.
Im Wiki (https://wiki.warpzone.ms/intern:diskussionsthemen#diskussionsthemen_naechstes_plenum_automatische_einladung)
stehen folgende Themen:
Die Teilnahme ist natürlich auch remote möglich unter
https://jitsi.dorf-post.de/warpzone-plenum möglich.
{chr(10).join(topics)}
Viele Grüße und bis Dienstag,
Die Teilnahme ist natürlich auch remote möglich unter
https://jitsi.dorf-post.de/warpzone-plenum möglich.
sendmail_plenum.py
"""
Viele Grüße und bis Dienstag,
msg = EmailMessage()
msg['Subject'] = f'Aktuelle Plenumsthemen für Dienstag ({str(date)} 20:00)'
msg['From'] = '{{noreply_email_user}}'
msg['To'] = 'intern@warpzone.ms'
msg['Date'] = formatdate(localtime=True)
msg.set_content(mail)
server = smtplib.SMTP('{{smtp_host}}', {{smtp_port}})
server.starttls()
server.login("{{noreply_email_user}}", "{{noreply_email_pass}}")
server.send_message(msg)
server.quit()
return True
sendmail_plenum.py
"""
def update_page(label):
with open("/srv/dokuwiki/data/data/pages/intern/diskussionsthemen.txt") as fp:
raw = fp.read().split('\n')
new_content = []
topic_replaced = False
for old_line in raw:
new_content.append(old_line)
msg = EmailMessage()
msg['Subject'] = f'Aktuelle Plenumsthemen für Dienstag ({str(d)} 20:00)'
msg['From'] = '{{noreply_email_user}}'
msg['To'] = 'intern@warpzone.ms'
msg['Date'] = formatdate(localtime=True)
msg.set_content(mail)
server = smtplib.SMTP('{{smtp_host}}', {{smtp_port}})
server.starttls()
server.login("{{noreply_email_user}}", "{{noreply_email_pass}}")
server.send_message(msg)
server.quit()
return True
if not topic_replaced and "====== 1." in old_line:
new_content.append(f"====== 1.5 {label} ======")
topic_replaced = True
with open("/srv/dokuwiki/data/data/pages/intern/diskussionsthemen.txt", "w") as fp:
fp.write("\n".join(new_content))
success = False
try:
success = do_work()
wait_until_unlocked()
topics = get_topics()
if (len(topics) != 0):
# calculate date of next tuesday
date = datetime.date.today()
while date.strftime('%a') != 'Tue':
date += datetime.timedelta(1)
success = send_mail(topics, date)
label = f"Diskussionsthemen für {date}"
if success:
label += f" (bereits eingeladen)"
else:
label += f" (Einladung fehlgeschlagen)"
success = update_page(label)
else:
success = True
except:
success = False
raise
finally:
requests.get("{{ healthchecks_url }}" if success else "{{ healthchecks_url }}" + "/fail")
......@@ -5,7 +5,7 @@
- { path: /srv/hackmd/mysql_root_pass, length: 24 }
- { path: /srv/hackmd/mysql_user_pass, length: 12 }
- { path: /srv/hackmd/hackmd_session_secret, length: 32 }
- { path: /srv/ldap/secret/ldap_readonly_pass, length: -1 }
- { path: /srv/hackmd/oauth_client_secret, length: 32 }
- name: create folder struct for hackmd
......
......@@ -15,15 +15,17 @@ services:
CMD_ALLOW_ANONYMOUS_EDITS: "true"
CMD_DEFAULT_PERMISSION: "freely"
CMD_ALLOW_FREEURL: "true"
CMD_LDAP_URL: "ldap://{{ ldap_ip_ext }}:389"
CMD_LDAP_BINDDN: "{{ ldap_readonly_bind_dn }}"
CMD_LDAP_BINDCREDENTIALS: "{{ ldap_readonly_pass }}"
CMD_LDAP_SEARCHBASE: "{{ ldap_base_dn }}"
CMD_LDAP_SEARCHFILTER: "(&(uid={% raw %}{{username}}{% endraw %})(objectClass=inetOrgPerson)(memberof=CN=active,OU=groups,DC=warpzone,DC=ms))"
CMD_LDAP_SEARCHATTRIBUTES: "uid"
CMD_LDAP_USERIDFIELD: "uid"
CMD_LDAP_USERNAMEFIELD: "uid"
CMD_EMAIL: "false"
CMD_OAUTH2_USER_PROFILE_URL: "{{ oauth_global.userinfo_url }}"
CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR: "preferred_username"
CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR: "preferred_username"
CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR: "email"
CMD_OAUTH2_TOKEN_URL: "{{ oauth_global.token_url }}"
CMD_OAUTH2_AUTHORIZATION_URL: "{{ oauth_global.authorize_url }}"
CMD_OAUTH2_CLIENT_ID: "hackmd"
CMD_OAUTH2_CLIENT_SECRET: "{{ oauth_client_secret }}"
CMD_OAUTH2_PROVIDERNAME: "Login with uffd"
CMD_OAUTH2_SCOPE: "openid email profile"
labels:
- traefik.enable=true
- traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
......
......@@ -36,7 +36,13 @@ RUN cd /opt/ \
RUN cd /opt/ \
&& git clone https://github.com/matteocorti/check_rbl.git \
&& cd /opt/check_rbl/ \
&& git checkout v1.6.3
&& git checkout v1.7.6 \
&& sed -i '/server=cbl.abuseat.org/d' /opt/check_rbl/check_rbl.ini \
&& sed -i '/server=pbl.spamhaus.org/d' /opt/check_rbl/check_rbl.ini \
&& sed -i '/server=xbl.spamhaus.org/d' /opt/check_rbl/check_rbl.ini \
&& sed -i '/server=sbl.spamhaus.org/d' /opt/check_rbl/check_rbl.ini \
&& sed -i '/server=sbl-xbl.spamhaus.org/d' /opt/check_rbl/check_rbl.ini \
&& sed -i '/server=zen.spamhaus.org/d' /opt/check_rbl/check_rbl.ini
# prom2json -- needed for check_metric_value
RUN cd /opt/ \
......
......@@ -29,7 +29,7 @@ object Host "wz-sw-access" {
object Host "wz-sw-dach" {
import "generic-host"
address = "192.168.0.4"
address = "192.168.0.6"
groups = [ "network" ]
}
......
- name: create folder for {{ servicename }}
file:
path: "{{ item }}"
state: "directory"
with_items:
- "{{ basedir }}"
- name: create folder for {{ servicename }} data
file:
path: "{{ item }}"
state: "directory"
mode: '0777'
with_items:
- "{{ basedir }}/data"
- "{{ basedir }}/cfg"
- name: privatebin config erstellen
template:
src: "conf.php"
dest: "{{ basedir }}/cfg/conf.php"
register: config
- name: Docker Compose Konfig-Datei erstellen
template:
src: "{{ item }}"
dest: "{{ basedir }}/{{ item }}"
with_items:
- "docker-compose.yml"
register: config
- name: stop {{ servicename }} docker
community.docker.docker_compose_v2:
project_src: "{{ basedir }}/"
state: absent
when: config.changed
- name: start {{ servicename }} docker
community.docker.docker_compose_v2:
project_src: "{{ basedir }}/"
state: present
\ No newline at end of file
;<?php http_response_code(403); /*
; config file for PrivateBin
;
; An explanation of each setting can be find online at https://github.com/PrivateBin/PrivateBin/wiki/Configuration.
[main]
; (optional) set a project name to be displayed on the website
name = "warpzone PrivateBin"
; The full URL, with the domain name and directories that point to the
; PrivateBin files, including an ending slash (/). This URL is essential to
; allow Opengraph images to be displayed on social networks.
basepath = "https://privatebin.webdiscount.net/"
; enable or disable the discussion feature, defaults to true
discussion = false
; preselect the discussion feature, defaults to false
opendiscussion = false
; enable or disable the display of dates & times in the comments, defaults to true
; Note that internally the creation time will still get tracked in order to sort
; the comments by creation time, but you can choose not to display them.
; discussiondatedisplay = false
; enable or disable the password feature, defaults to true
password = true
; enable or disable the file upload feature, defaults to false
fileupload = true
; preselect the burn-after-reading feature, defaults to false
burnafterreadingselected = true
; which display mode to preselect by default, defaults to "plaintext"
; make sure the value exists in [formatter_options]
defaultformatter = "plaintext"
; (optional) set a syntax highlighting theme, as found in css/prettify/
; syntaxhighlightingtheme = "sons-of-obsidian"
; size limit per paste or comment in bytes, defaults to 10 Mebibytes
sizelimit = 10485760
; by default PrivateBin use "bootstrap" template (tpl/bootstrap.php).
; Optionally you can enable the template selection menu, which uses
; a session cookie to store the choice until the browser is closed.
templateselection = true
; List of available for selection templates when "templateselection" option is enabled
availabletemplates[] = "bootstrap"
availabletemplates[] = "bootstrap-dark"
availabletemplates[] = "bootstrap5"
; set the template your installs defaults to, defaults to "bootstrap" (tpl/bootstrap.php), also
; available are "page" (tpl/page.php), the classic ZeroBin style and several
; bootstrap variants: "bootstrap-dark", "bootstrap-compact", "bootstrap-page",
; which can be combined with "-dark" and "-compact" for "bootstrap-dark-page",
; "bootstrap-compact-page" and finally "bootstrap5" (tpl/bootstrap5.php) - previews at:
; https://privatebin.info/screenshots.html
template = "bootstrap5"
; (optional) info text to display
; use single, instead of double quotes for HTML attributes
;info = "More information on the <a href='https://privatebin.info/'>project page</a>."
; (optional) notice to display
notice = "Note: Data may be deleted anytime. Kittens will die if you abuse this service."
; by default PrivateBin will guess the visitors language based on the browsers
; settings. Optionally you can enable the language selection menu, which uses
; a session cookie to store the choice until the browser is closed.
languageselection = false
; set the language your installs defaults to, defaults to English
; if this is set and language selection is disabled, this will be the only language
; languagedefault = "en"
; (optional) URL shortener address to offer after a new paste is created.
; It is suggested to only use this with self-hosted shorteners as this will leak
; the pastes encryption key.
; urlshortener = "https://shortener.example.com/api?link="
; (optional) Let users create a QR code for sharing the paste URL with one click.
; It works both when a new paste is created and when you view a paste.
; qrcode = true
; (optional) Let users send an email sharing the paste URL with one click.
; It works both when a new paste is created and when you view a paste.
; email = true
; (optional) IP based icons are a weak mechanism to detect if a comment was from
; a different user when the same username was used in a comment. It might get
; used to get the IP of a comment poster if the server salt is leaked and a
; SHA512 HMAC rainbow table is generated for all (relevant) IPs.
; Can be set to one these values:
; "none" / "identicon" (default) / "jdenticon" / "vizhash".
; icon = "none"
; Content Security Policy headers allow a website to restrict what sources are
; allowed to be accessed in its context. You need to change this if you added
; custom scripts from third-party domains to your templates, e.g. tracking
; scripts or run your site behind certain DDoS-protection services.
; Check the documentation at https://content-security-policy.com/
; Notes:
; - If you use any bootstrap theme, you can remove the allow-popups from the
; sandbox restrictions.
; - If you use the bootstrap5 theme, you must change default-src to 'self' to
; enable display of the svg icons
; - By default this disallows to load images from third-party servers, e.g. when
; they are embedded in pastes. If you wish to allow that, you can adjust the
; policy here. See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-it-load-embedded-images
; for details.
; - The 'wasm-unsafe-eval' is used to enable webassembly support (used for zlib
; compression). You can remove it if compression doesn't need to be supported.
; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; font-src 'self'; frame-ancestors 'none'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads"
; stay compatible with PrivateBin Alpha 0.19, less secure
; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of
; sha256 in HMAC for the deletion token
; zerobincompatibility = false
; Enable or disable the warning message when the site is served over an insecure
; connection (insecure HTTP instead of HTTPS), defaults to true.
; Secure transport methods like Tor and I2P domains are automatically whitelisted.
; It is **strongly discouraged** to disable this.
; See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-an-error-about-an-insecure-connection for more information.
httpwarning = true
; Pick compression algorithm or disable it. Only applies to pastes/comments
; created after changing the setting.
; Can be set to one these values: "none" / "zlib" (default).
; compression = "zlib"
[expire]
; expire value that is selected per default
; make sure the value exists in [expire_options]
default = "1week"
[expire_options]
; Set each one of these to the number of seconds in the expiration period,
; or 0 if it should never expire
5min = 300
10min = 600
1hour = 3600
1day = 86400
1week = 604800
; Well this is not *exactly* one month, it's 30 days:
1month = 2592000
1year = 31536000
never = 0
[formatter_options]
; Set available formatters, their order and their labels
plaintext = "Plain Text"
syntaxhighlighting = "Source Code"
markdown = "Markdown"
[traffic]
; time limit between calls from the same IP address in seconds
; Set this to 0 to disable rate limiting.
limit = 5
; (optional) Set IPs addresses (v4 or v6) or subnets (CIDR) which are exempted
; from the rate-limit. Invalid IPs will be ignored. If multiple values are to
; be exempted, the list needs to be comma separated. Leave unset to disable
; exemptions.
; exempted = "1.2.3.4,10.10.10/24"
; (optional) If you want only some source IP addresses (v4 or v6) or subnets
; (CIDR) to be allowed to create pastes, set these here. Invalid IPs will be
; ignored. If multiple values are to be exempted, the list needs to be comma
; separated. Leave unset to allow anyone to create pastes.
; creators = "1.2.3.4,10.10.10/24"
; (optional) if your website runs behind a reverse proxy or load balancer,
; set the HTTP header containing the visitors IP address, i.e. X_FORWARDED_FOR
header = "X_FORWARDED_FOR"
[purge]
; minimum time limit between two purgings of expired pastes, it is only
; triggered when pastes are created
; Set this to 0 to run a purge every time a paste is created.
limit = 300
; maximum amount of expired pastes to delete in one purge
; Set this to 0 to disable purging. Set it higher, if you are running a large
; site
batchsize = 10
[model]
; name of data model class to load and directory for storage
; the default model "Filesystem" stores everything in the filesystem
class = Filesystem
[model_options]
dir = PATH "data"
;[model]
; example of a Google Cloud Storage configuration
;class = GoogleCloudStorage
;[model_options]
;bucket = "my-private-bin"
;prefix = "pastes"
;uniformacl = false
;[model]
; example of DB configuration for MySQL
;class = Database
;[model_options]
;dsn = "mysql:host=localhost;dbname=privatebin;charset=UTF8"
;tbl = "privatebin_" ; table prefix
;usr = "privatebin"
;pwd = "Z3r0P4ss"
;opt[12] = true ; PDO::ATTR_PERSISTENT
;[model]
; example of DB configuration for SQLite
;class = Database
;[model_options]
;dsn = "sqlite:" PATH "data/db.sq3"
;usr = null
;pwd = null
;opt[12] = true ; PDO::ATTR_PERSISTENT
;[model]
; example of DB configuration for PostgreSQL
;class = Database
;[model_options]
;dsn = "pgsql:host=localhost;dbname=privatebin"
;tbl = "privatebin_" ; table prefix
;usr = "privatebin"
;pwd = "Z3r0P4ss"
;opt[12] = true ; PDO::ATTR_PERSISTENT
;[model]
; example of S3 configuration for Rados gateway / CEPH
;class = S3Storage
;[model_options]
;region = ""
;version = "2006-03-01"
;endpoint = "https://s3.my-ceph.invalid"
;use_path_style_endpoint = true
;bucket = "my-bucket"
;accesskey = "my-rados-user"
;secretkey = "my-rados-pass"
;[model]
; example of S3 configuration for AWS
;class = S3Storage
;[model_options]
;region = "eu-central-1"
;version = "latest"
;bucket = "my-bucket"
;accesskey = "access key id"
;secretkey = "secret access key"
;[model]
; example of S3 configuration for AWS using its SDK default credential provider chain
; if relying on environment variables, the AWS SDK will look for the following:
; - AWS_ACCESS_KEY_ID
; - AWS_SECRET_ACCESS_KEY
; - AWS_SESSION_TOKEN (if needed)
; for more details, see https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials.html#default-credential-chain
;class = S3Storage
;[model_options]
;region = "eu-central-1"
;version = "latest"
;bucket = "my-bucket"
;[yourls]
; When using YOURLS as a "urlshortener" config item:
; - By default, "urlshortener" will point to the YOURLS API URL, with or without
; credentials, and will be visible in public on the PrivateBin web page.
; Only use this if you allow short URL creation without credentials.
; - Alternatively, using the parameters in this section ("signature" and
; "apiurl"), "urlshortener" needs to point to the base URL of your PrivateBin
; instance with "?shortenviayourls&link=" appended. For example:
; urlshortener = "${basepath}?shortenviayourls&link="
; This URL will in turn call YOURLS on the server side, using the URL from
; "apiurl" and the "access signature" from the "signature" parameters below.
; (optional) the "signature" (access key) issued by YOURLS for the using account
; signature = ""
; (optional) the URL of the YOURLS API, called to shorten a PrivateBin URL
; apiurl = "https://yourls.example.com/yourls-api.php"
;[sri]
; Subresource integrity (SRI) hashes used in template files. Uncomment and set
; these for all js files used. See:
; https://github.com/PrivateBin/PrivateBin/wiki/FAQ#user-content-how-to-make-privatebin-work-when-i-have-changed-some-javascript-files
;js/privatebin.js = "sha512-[…]"
\ No newline at end of file
services:
app:
image: privatebin/nginx-fpm-alpine:stable
volumes:
- "{{ basedir }}/data:/srv/data"
- "{{ basedir }}/cfg:/srv/cfg"
networks:
- web
labels:
- traefik.enable=true
- traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
- traefik.http.routers.{{ servicename }}.entrypoints=websecure
- traefik.http.services.{{ servicename }}.loadbalancer.server.port=8080
networks:
web:
external: true
\ No newline at end of file