mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-09-09 19:57:16 +02:00
Compare commits
9 Commits
ee0561db72
...
8cd7379419
Author | SHA1 | Date | |
---|---|---|---|
8cd7379419 | |||
dc6454e910 | |||
1df0e38f06 | |||
c3575e5647 | |||
7950a3f517 | |||
52f467c15c | |||
9f1d153053 | |||
1858c1970f | |||
06b864ad52 |
@@ -6,7 +6,8 @@ import os
|
|||||||
import datetime
|
import datetime
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def run_ansible_playbook(inventory, playbook, modes, limit=None, password_file=None, verbose=0, skip_tests=False):
|
|
||||||
|
def run_ansible_playbook(inventory, playbook, modes, limit=None, allowed_applications=None, password_file=None, verbose=0, skip_tests=False):
|
||||||
start_time = datetime.datetime.now()
|
start_time = datetime.datetime.now()
|
||||||
print(f"\n▶️ Script started at: {start_time.isoformat()}\n")
|
print(f"\n▶️ Script started at: {start_time.isoformat()}\n")
|
||||||
|
|
||||||
@@ -22,6 +23,15 @@ def run_ansible_playbook(inventory, playbook, modes, limit=None, password_file=N
|
|||||||
if limit:
|
if limit:
|
||||||
cmd.extend(["--limit", limit])
|
cmd.extend(["--limit", limit])
|
||||||
|
|
||||||
|
# Pass application IDs parameter as extra var if provided
|
||||||
|
if allowed_applications:
|
||||||
|
joined = ",".join(allowed_applications)
|
||||||
|
cmd.extend(["-e", f"allowed_applications={joined}"])
|
||||||
|
else:
|
||||||
|
# No IDs provided: execute all applications defined in the inventory
|
||||||
|
cmd.extend(["-e", "allowed_applications=all"])
|
||||||
|
|
||||||
|
# Pass other mode flags
|
||||||
for key, value in modes.items():
|
for key, value in modes.items():
|
||||||
val = str(value).lower() if isinstance(value, bool) else str(value)
|
val = str(value).lower() if isinstance(value, bool) else str(value)
|
||||||
cmd.extend(["-e", f"{key}={val}"])
|
cmd.extend(["-e", f"{key}={val}"])
|
||||||
@@ -43,6 +53,7 @@ def run_ansible_playbook(inventory, playbook, modes, limit=None, password_file=N
|
|||||||
duration = end_time - start_time
|
duration = end_time - start_time
|
||||||
print(f"⏱️ Total execution time: {duration}\n")
|
print(f"⏱️ Total execution time: {duration}\n")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
@@ -99,6 +110,12 @@ def main():
|
|||||||
"--skip-validation", action="store_true",
|
"--skip-validation", action="store_true",
|
||||||
help="Skip inventory validation before deployment."
|
help="Skip inventory validation before deployment."
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--id",
|
||||||
|
nargs="+",
|
||||||
|
default=[],
|
||||||
|
help="List of application_id's for partial deploy. If not set, all application IDs defined in the inventory will be executed."
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-v", "--verbose", action="count", default=0,
|
"-v", "--verbose", action="count", default=0,
|
||||||
help="Increase verbosity level. Multiple -v flags increase detail (e.g., -vvv for maximum log output)."
|
help="Increase verbosity level. Multiple -v flags increase detail (e.g., -vvv for maximum log output)."
|
||||||
@@ -134,6 +151,7 @@ def main():
|
|||||||
playbook=playbook_file,
|
playbook=playbook_file,
|
||||||
modes=modes,
|
modes=modes,
|
||||||
limit=args.limit,
|
limit=args.limit,
|
||||||
|
allowed_applications=args.id,
|
||||||
password_file=args.password_file,
|
password_file=args.password_file,
|
||||||
verbose=args.verbose,
|
verbose=args.verbose,
|
||||||
skip_tests=args.skip_tests
|
skip_tests=args.skip_tests
|
||||||
|
@@ -115,7 +115,7 @@ def generate_playbook_entries(roles_dir, prefix=None):
|
|||||||
role = roles[role_name]
|
role = roles[role_name]
|
||||||
entries.append(
|
entries.append(
|
||||||
f"- name: setup {role['application_id']}\n"
|
f"- name: setup {role['application_id']}\n"
|
||||||
f" when: ('{role['application_id']}' in group_names)\n"
|
f" when: ('{role['application_id']}' | application_allowed(group_names, allowed_applications))\n"
|
||||||
f" include_role:\n"
|
f" include_role:\n"
|
||||||
f" name: {role['role_name']}\n"
|
f" name: {role['role_name']}\n"
|
||||||
)
|
)
|
||||||
|
44
filter_plugins/application_allowed.py
Normal file
44
filter_plugins/application_allowed.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Provides a filter to control which applications (roles) should be deployed
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleFilterError
|
||||||
|
|
||||||
|
|
||||||
|
def application_allowed(application_id: str, group_names: list, allowed_applications: list = []):
|
||||||
|
"""
|
||||||
|
Return True if:
|
||||||
|
- application_id exists in group_names, AND
|
||||||
|
- either allowed_applications is not provided (or empty), OR application_id is in allowed_applications.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
application_id (str): Name of the application/role to check.
|
||||||
|
group_names (list): List of groups the current host belongs to.
|
||||||
|
allowed_applications (list, optional): List of application IDs to allow.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if this application is allowed to deploy, False otherwise.
|
||||||
|
"""
|
||||||
|
# Ensure group_names is iterable
|
||||||
|
if not isinstance(group_names, (list, tuple)):
|
||||||
|
raise AnsibleFilterError(f"Expected group_names to be a list, str or tuple, got {type(group_names)}")
|
||||||
|
|
||||||
|
# Must be part of the host's groups
|
||||||
|
if application_id not in group_names:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# If allowed_applications provided, only allow if ID is in that list
|
||||||
|
if allowed_applications:
|
||||||
|
if not isinstance(allowed_applications, (list, tuple, str)):
|
||||||
|
raise AnsibleFilterError(f"allowed_applications must be a list or tuple if provided, got {type(allowed_applications)}")
|
||||||
|
return application_id in allowed_applications
|
||||||
|
|
||||||
|
# No filter provided → allow all in group_names
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class FilterModule(object):
|
||||||
|
def filters(self):
|
||||||
|
return {
|
||||||
|
'application_allowed': application_allowed,
|
||||||
|
}
|
@@ -54,4 +54,7 @@ certbot_cert_path: "/etc/letsencrypt/live" # Path contain
|
|||||||
docker_restart_policy: "unless-stopped"
|
docker_restart_policy: "unless-stopped"
|
||||||
|
|
||||||
# helper
|
# helper
|
||||||
_applications_nextcloud_oidc_flavor: "{{ applications.nextcloud.oidc.flavor | default('oidc_login' if applications.nextcloud.features.ldap | default(true) else 'sociallogin') }}"
|
_applications_nextcloud_oidc_flavor: "{{ applications.nextcloud.oidc.flavor | default('oidc_login' if applications.nextcloud.features.ldap | default(true) else 'sociallogin') }}"
|
||||||
|
|
||||||
|
# default value if not set via CLI (-e) or in playbook vars
|
||||||
|
allowed_applications: []
|
||||||
|
@@ -39,4 +39,6 @@ defaults_oidc:
|
|||||||
username: "preferred_username"
|
username: "preferred_username"
|
||||||
given_name: "givenName"
|
given_name: "givenName"
|
||||||
family_name: "surname"
|
family_name: "surname"
|
||||||
email: "email"
|
email: "email"
|
||||||
|
claims:
|
||||||
|
groups: "groups"
|
||||||
|
@@ -54,14 +54,6 @@ ldap:
|
|||||||
# – Keeping these distinct prevents accidental use of config credentials
|
# – Keeping these distinct prevents accidental use of config credentials
|
||||||
# for ordinary user/group operations, and vice versa.
|
# for ordinary user/group operations, and vice versa.
|
||||||
|
|
||||||
attributes:
|
|
||||||
# Attribut to identify the user
|
|
||||||
user_id: "{{ _ldap_user_id }}"
|
|
||||||
mail: "mail"
|
|
||||||
fullname: "cn"
|
|
||||||
firstname: "givenname"
|
|
||||||
surname: "sn"
|
|
||||||
ssh_public_key: "sshPublicKey"
|
|
||||||
# Password to access dn.bind
|
# Password to access dn.bind
|
||||||
bind_credential: "{{ applications.ldap.credentials.administrator_database_password }}"
|
bind_credential: "{{ applications.ldap.credentials.administrator_database_password }}"
|
||||||
server:
|
server:
|
||||||
@@ -71,21 +63,30 @@ ldap:
|
|||||||
security: "" #TLS, SSL - Leave empty for none
|
security: "" #TLS, SSL - Leave empty for none
|
||||||
network:
|
network:
|
||||||
local: "{{applications.ldap.network.docker}}" # Uses the application configuration to define if local network should be available or not
|
local: "{{applications.ldap.network.docker}}" # Uses the application configuration to define if local network should be available or not
|
||||||
user_objects:
|
user:
|
||||||
structural:
|
objects:
|
||||||
- person # Structural Classes define the core identity of an entry:
|
structural:
|
||||||
# • Specify mandatory attributes (e.g. sn, cn)
|
- person # Structural Classes define the core identity of an entry:
|
||||||
# • Each entry must have exactly one structural class
|
# • Specify mandatory attributes (e.g. sn, cn)
|
||||||
- inetOrgPerson # An extension of person adding internet-related attributes
|
# • Each entry must have exactly one structural class
|
||||||
# (e.g. mail, employeeNumber)
|
- inetOrgPerson # An extension of person adding internet-related attributes
|
||||||
- posixAccount # Provides UNIX account attributes (uidNumber, gidNumber,
|
# (e.g. mail, employeeNumber)
|
||||||
# homeDirectory)
|
- posixAccount # Provides UNIX account attributes (uidNumber, gidNumber,
|
||||||
auxiliary:
|
# homeDirectory)
|
||||||
- nextcloudUser # Auxiliary Classes attach optional attributes without
|
auxiliary:
|
||||||
# changing the entry’s structural role. Here they add
|
nextloud_user: "nextcloudUser" # Auxiliary Classes attach optional attributes without
|
||||||
# nextcloudQuota and nextcloudEnabled for Nextcloud.
|
# changing the entry’s structural role. Here they add
|
||||||
- ldapPublicKey # Allows storing SSH public keys for services like Gitea.
|
# nextcloudQuota and nextcloudEnabled for Nextcloud.
|
||||||
|
ssh_public_key: "ldapPublicKey" # Allows storing SSH public keys for services like Gitea.
|
||||||
|
attributes:
|
||||||
|
# Attribut to identify the user
|
||||||
|
id: "{{ _ldap_user_id }}"
|
||||||
|
mail: "mail"
|
||||||
|
fullname: "cn"
|
||||||
|
firstname: "givenname"
|
||||||
|
surname: "sn"
|
||||||
|
ssh_public_key: "sshPublicKey"
|
||||||
|
nextcloud_quota: "nextcloudQuota"
|
||||||
filters:
|
filters:
|
||||||
users:
|
users:
|
||||||
login: "(&{{ _ldap_filters_users_all }}({{_ldap_user_id}}=%{{_ldap_user_id}}))"
|
login: "(&{{ _ldap_filters_users_all }}({{_ldap_user_id}}=%{{_ldap_user_id}}))"
|
||||||
|
@@ -170,7 +170,7 @@ OAUTH2_REDIRECT=
|
|||||||
# LDAP_SERVER=ldap.example.com
|
# LDAP_SERVER=ldap.example.com
|
||||||
# LDAP_PORT=389
|
# LDAP_PORT=389
|
||||||
# LDAP_METHOD=plain
|
# LDAP_METHOD=plain
|
||||||
# LDAP_UID={{ldap.attributes.user_id}}
|
# LDAP_UID={{ldap.user.attributes.id}}
|
||||||
# LDAP_BASE=dc=example,dc=com
|
# LDAP_BASE=dc=example,dc=com
|
||||||
# LDAP_AUTH=simple
|
# LDAP_AUTH=simple
|
||||||
# LDAP_BIND_DN=cn=admin,dc=example,dc=com
|
# LDAP_BIND_DN=cn=admin,dc=example,dc=com
|
||||||
@@ -180,7 +180,7 @@ OAUTH2_REDIRECT=
|
|||||||
LDAP_SERVER="{{ldap.server.domain}}"
|
LDAP_SERVER="{{ldap.server.domain}}"
|
||||||
LDAP_PORT="{{ldap.server.port}}"
|
LDAP_PORT="{{ldap.server.port}}"
|
||||||
LDAP_METHOD=
|
LDAP_METHOD=
|
||||||
LDAP_UID={{ldap.attributes.user_id}}
|
LDAP_UID={{ldap.user.attributes.id}}
|
||||||
LDAP_BASE="{{ldap.dn.root}}"
|
LDAP_BASE="{{ldap.dn.root}}"
|
||||||
LDAP_BIND_DN="{{ldap.dn.administrator.data}}"
|
LDAP_BIND_DN="{{ldap.dn.administrator.data}}"
|
||||||
LDAP_AUTH=password
|
LDAP_AUTH=password
|
||||||
|
2
roles/docker-bookwyrm/Todo.md
Normal file
2
roles/docker-bookwyrm/Todo.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Todo
|
||||||
|
- Implement https://joinbookwyrm.com/de/
|
1
roles/docker-bookwyrm/vars/main.yml
Normal file
1
roles/docker-bookwyrm/vars/main.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
application_id: bookwyrm
|
2
roles/docker-chess/Readme.md
Normal file
2
roles/docker-chess/Readme.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Todo
|
||||||
|
- Implement https://joinbookwyrm.com/de/
|
1
roles/docker-chess/vars/main.yml
Normal file
1
roles/docker-chess/vars/main.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
application_id: chess
|
@@ -1,5 +1,11 @@
|
|||||||
# Administration
|
# Administration
|
||||||
|
|
||||||
|
## CLI
|
||||||
|
The CLI you reach via
|
||||||
|
```bash
|
||||||
|
docker compose exec --user www-data application bin/console
|
||||||
|
```
|
||||||
|
|
||||||
## Full Reset 🚫➡️✅
|
## Full Reset 🚫➡️✅
|
||||||
|
|
||||||
The following environment variables need to be defined for successful operation:
|
The following environment variables need to be defined for successful operation:
|
||||||
|
@@ -21,3 +21,4 @@ galaxy_info:
|
|||||||
run_after:
|
run_after:
|
||||||
- docker-matomo
|
- docker-matomo
|
||||||
- docker-keycloak
|
- docker-keycloak
|
||||||
|
- docker-ldap
|
||||||
|
@@ -3,6 +3,17 @@
|
|||||||
include_role:
|
include_role:
|
||||||
name: docker-central-database
|
name: docker-central-database
|
||||||
|
|
||||||
|
- name: "create {{ friendica_host_ldap_config }}"
|
||||||
|
template:
|
||||||
|
src: "ldapauth.config.php.j2"
|
||||||
|
dest: "{{ friendica_host_ldap_config }}"
|
||||||
|
mode: '644'
|
||||||
|
owner: root
|
||||||
|
group: 33
|
||||||
|
force: yes
|
||||||
|
notify: docker compose up
|
||||||
|
when: applications | is_feature_enabled('ldap',application_id)
|
||||||
|
|
||||||
- name: "include role nginx-domain-setup for {{application_id}}"
|
- name: "include role nginx-domain-setup for {{application_id}}"
|
||||||
include_role:
|
include_role:
|
||||||
name: nginx-domain-setup
|
name: nginx-domain-setup
|
||||||
@@ -11,3 +22,37 @@
|
|||||||
http_port: "{{ ports.localhost.http[application_id] }}"
|
http_port: "{{ ports.localhost.http[application_id] }}"
|
||||||
|
|
||||||
- include_tasks: "{{ playbook_dir }}/roles/docker-compose/tasks/create-files.yml"
|
- include_tasks: "{{ playbook_dir }}/roles/docker-compose/tasks/create-files.yml"
|
||||||
|
|
||||||
|
- name: Build friendica_addons based on features
|
||||||
|
set_fact:
|
||||||
|
friendica_addons: >-
|
||||||
|
{{
|
||||||
|
friendica_addons | default([])
|
||||||
|
+ [{
|
||||||
|
'name': item.key,
|
||||||
|
'enabled': (
|
||||||
|
applications[application_id].features.oidc
|
||||||
|
if item.key == 'keycloakpassword'
|
||||||
|
else applications[application_id].features.ldap
|
||||||
|
if item.key == 'ldapauth'
|
||||||
|
else (item.value.enabled if item.value is mapping and 'enabled' in item.value else False)
|
||||||
|
)
|
||||||
|
}]
|
||||||
|
}}
|
||||||
|
loop: "{{ applications[application_id].addons | dict2items }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.key }}"
|
||||||
|
|
||||||
|
- name: Ensure Friendica addons are in sync
|
||||||
|
command: >
|
||||||
|
docker compose exec --user www-data
|
||||||
|
application
|
||||||
|
bin/console addon
|
||||||
|
{{ 'enable' if item.enabled else 'disable' }}
|
||||||
|
{{ item.name }}
|
||||||
|
args:
|
||||||
|
chdir: "{{ docker_compose.directories.instance }}"
|
||||||
|
loop: "{{ friendica_addons }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.name }}"
|
||||||
|
|
||||||
|
@@ -6,8 +6,9 @@ services:
|
|||||||
image: "{{ applications[application_id].images.friendica }}"
|
image: "{{ applications[application_id].images.friendica }}"
|
||||||
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
|
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
|
||||||
volumes:
|
volumes:
|
||||||
- html:/var/www/html
|
- html:{{ friendica_application_base }}
|
||||||
- data:/var/www/data
|
- data:/var/www/data # I assume that this one is unnessecarry
|
||||||
|
- {{ friendica_host_ldap_config }}:{{ friendica_docker_ldap_config }}:ro
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:{{ports.localhost.http[application_id]}}:80"
|
- "127.0.0.1:{{ports.localhost.http[application_id]}}:80"
|
||||||
|
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
# The configuration options can be found here:
|
# The configuration options can be found here:
|
||||||
# @see https://hub.docker.com/_/friendica
|
# @see https://hub.docker.com/_/friendica
|
||||||
|
|
||||||
FRIENDICA_URL= https://{{domains | get_domain(application_id)}}
|
FRIENDICA_URL=https://{{domains | get_domain(application_id)}}
|
||||||
HOSTNAME= {{domains | get_domain(application_id)}}
|
HOSTNAME={{domains | get_domain(application_id)}}
|
||||||
FRIENDICA_NO_VALIDATION={{no_validation | lower}}
|
FRIENDICA_NO_VALIDATION={{friendica_no_validation | lower}}
|
||||||
|
|
||||||
# Debugging
|
# Debugging
|
||||||
FRIENDICA_DEBUGGING= {% if enable_debug | bool %}true{% else %}false{% endif %}
|
FRIENDICA_DEBUGGING={% if enable_debug | bool %}true{% else %}false{% endif %}{{"\n"}}
|
||||||
FRIENDICA_LOGLEVEL= 5
|
FRIENDICA_LOGLEVEL={% if enable_debug | bool %}9{% else %}5{% endif %}{{"\n"}}
|
||||||
FRIENDICA_LOGGER= syslog
|
FRIENDICA_LOGGER=syslog
|
||||||
|
|
||||||
# Database Configuration
|
# Database Configuration
|
||||||
MYSQL_HOST= "{{database_host}}:{{database_port}}"
|
MYSQL_HOST= "{{database_host}}:{{database_port}}"
|
||||||
|
51
roles/docker-friendica/templates/ldapauth.config.php.j2
Normal file
51
roles/docker-friendica/templates/ldapauth.config.php.j2
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
// Source: https://git.friendi.ca/friendica/friendica-addons/src/branch/develop/ldapauth
|
||||||
|
|
||||||
|
// Warning: Don't change this file! It only holds the default config values for this addon.
|
||||||
|
// Instead, copy this file to config/ldapauth.config.php in your Friendica directory and set the correct values there
|
||||||
|
|
||||||
|
return [
|
||||||
|
'ldapauth' => [
|
||||||
|
// ldap_server (String)
|
||||||
|
// ldap hostname server - required
|
||||||
|
// Example: ldap_server = host.example.com
|
||||||
|
'ldap_server' => '{{ ldap.server.uri }}',
|
||||||
|
|
||||||
|
// ldap_binddn (String)
|
||||||
|
// admin dn - optional - only if ldap server dont have anonymous access
|
||||||
|
// Example: ldap_binddn = cn=admin,dc=example,dc=com
|
||||||
|
'ldap_binddn' => '{{ ldap.dn.administrator.data }}',
|
||||||
|
|
||||||
|
// ldap_bindpw (String)
|
||||||
|
// admin password - optional - only if ldap server dont have anonymous access
|
||||||
|
'ldap_bindpw' => '{{ ldap.bind_credential }}',
|
||||||
|
|
||||||
|
// ldap_searchdn (String)
|
||||||
|
// dn to search users - required
|
||||||
|
// Example: ldap_searchdn = ou=users,dc=example,dc=com
|
||||||
|
'ldap_searchdn' => '{{ ldap.dn.ou.users }}',
|
||||||
|
|
||||||
|
// ldap_userattr (String)
|
||||||
|
// attribute to find username - required
|
||||||
|
// Example: ldap_userattr = uid
|
||||||
|
'ldap_userattr' => '{{ ldap.user.attributes.id }}',
|
||||||
|
|
||||||
|
// ldap_group (String)
|
||||||
|
// DN of the group whose member can auth on Friendica - optional
|
||||||
|
'ldap_group' =>'',
|
||||||
|
|
||||||
|
// ldap_autocreateaccount (Boolean)
|
||||||
|
// To create Friendica account if user exists in ldap
|
||||||
|
// Requires an email and a simple (beautiful) nickname on user ldap object
|
||||||
|
// active account creation - optional - default true
|
||||||
|
'ldap_autocreateaccount' => true,
|
||||||
|
|
||||||
|
// ldap_autocreateaccount_emailattribute (String)
|
||||||
|
// attribute to get email - optional - default : 'mail'
|
||||||
|
'ldap_autocreateaccount_emailattribute' => '{{ ldap.user.attributes.mail }}',
|
||||||
|
|
||||||
|
// ldap_autocreateaccount_nameattribute (String)
|
||||||
|
// attribute to get nickname - optional - default : 'givenName'
|
||||||
|
'ldap_autocreateaccount_nameattribute' => '{{ ldap.user.attributes.firstname }}',
|
||||||
|
],
|
||||||
|
];
|
@@ -2,10 +2,27 @@ images:
|
|||||||
friendica: "friendica:latest"
|
friendica: "friendica:latest"
|
||||||
features:
|
features:
|
||||||
matomo: true
|
matomo: true
|
||||||
css: true
|
css: false # Temporary deactivated
|
||||||
portfolio_iframe: true
|
portfolio_iframe: true
|
||||||
oidc: true
|
oidc: false # Implementation doesn't work yet
|
||||||
central_database: true
|
central_database: true
|
||||||
|
ldap: true
|
||||||
|
oauth2: false # No special login side which could be protected, use 2FA of Friendica instead
|
||||||
domains:
|
domains:
|
||||||
aliases:
|
canonical:
|
||||||
- "social.{{ primary_domain }}"
|
- "social.{{ primary_domain }}"
|
||||||
|
csp:
|
||||||
|
flags:
|
||||||
|
script-src-elem:
|
||||||
|
unsafe-inline: true
|
||||||
|
script-src:
|
||||||
|
unsafe-inline: true
|
||||||
|
unsafe-eval: true
|
||||||
|
style-src:
|
||||||
|
unsafe-inline: true
|
||||||
|
oauth2_proxy:
|
||||||
|
application: "application"
|
||||||
|
port: "80"
|
||||||
|
addons:
|
||||||
|
keycloakpassword:
|
||||||
|
ldapauth:
|
@@ -1,3 +1,8 @@
|
|||||||
application_id: "friendica"
|
application_id: "friendica"
|
||||||
database_type: "mariadb"
|
database_type: "mariadb"
|
||||||
no_validation: "{{ applications[application_id].features.oidc }}" # Email validation is not neccessary if OIDC is active
|
|
||||||
|
friendica_no_validation: "{{ applications[application_id].features.oidc }}" # Email validation is not neccessary if OIDC is active
|
||||||
|
friendica_application_base: "/var/www/html"
|
||||||
|
friendica_docker_ldap_config: "{{friendica_application_base}}/config/ldapauth.config.php"
|
||||||
|
friendica_host_ldap_config: "{{ docker_compose.directories.volumes }}ldapauth.config.php"
|
||||||
|
|
||||||
|
@@ -111,10 +111,10 @@ LDAP_ENABLED = True
|
|||||||
LDAP_SERVER_URI = "{{ ldap.server.uri }}"
|
LDAP_SERVER_URI = "{{ ldap.server.uri }}"
|
||||||
LDAP_BIND_DN = "{{ ldap.dn.administrator.data }}"
|
LDAP_BIND_DN = "{{ ldap.dn.administrator.data }}"
|
||||||
LDAP_BIND_PASSWORD = "{{ ldap.bind_credential }}"
|
LDAP_BIND_PASSWORD = "{{ ldap.bind_credential }}"
|
||||||
#LDAP_SEARCH_FILTER = "{{ ldap.filters.users.login | replace('%' ~ ldap.attributes.user_id, '{0}') }}"
|
#LDAP_SEARCH_FILTER = "{{ ldap.filters.users.login | replace('%' ~ ldap.user.attributes.id, '{0}') }}"
|
||||||
LDAP_START_TLS = False
|
LDAP_START_TLS = False
|
||||||
LDAP_ROOT_DN = "{{ldap.dn.root}}"
|
LDAP_ROOT_DN = "{{ldap.dn.root}}"
|
||||||
#LDAP_USER_ATTR_MAP = "first_name:{{ ldap.attributes.firstname }}, last_name:{{ ldap.attributes.surname }}, username:{{ ldap.attributes.user_id }}, email:{{ ldap.attributes.mail }}"
|
#LDAP_USER_ATTR_MAP = "first_name:{{ ldap.user.attributes.firstname }}, last_name:{{ ldap.user.attributes.surname }}, username:{{ ldap.user.attributes.id }}, email:{{ ldap.user.attributes.mail }}"
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@@ -9,9 +9,9 @@ gitea_ldap_auth_args:
|
|||||||
- '--bind-password "{{ ldap.bind_credential }}"'
|
- '--bind-password "{{ ldap.bind_credential }}"'
|
||||||
- '--user-search-base "{{ ldap.dn.ou.users }}"'
|
- '--user-search-base "{{ ldap.dn.ou.users }}"'
|
||||||
- '--user-filter "(&(objectClass=inetOrgPerson)(uid=%s))"'
|
- '--user-filter "(&(objectClass=inetOrgPerson)(uid=%s))"'
|
||||||
- '--username-attribute "{{ ldap.attributes.user_id }}"'
|
- '--username-attribute "{{ ldap.user.attributes.id }}"'
|
||||||
- '--firstname-attribute "{{ ldap.attributes.firstname }}"'
|
- '--firstname-attribute "{{ ldap.user.attributes.firstname }}"'
|
||||||
- '--surname-attribute "{{ ldap.attributes.surname }}"'
|
- '--surname-attribute "{{ ldap.user.attributes.surname }}"'
|
||||||
- '--email-attribute "{{ ldap.attributes.mail }}"'
|
- '--email-attribute "{{ ldap.user.attributes.mail }}"'
|
||||||
- '--public-ssh-key-attribute "{{ ldap.attributes.ssh_public_key }}"'
|
- '--public-ssh-key-attribute "{{ ldap.user.attributes.ssh_public_key }}"'
|
||||||
- '--synchronize-users'
|
- '--synchronize-users'
|
||||||
|
@@ -32,19 +32,19 @@
|
|||||||
set_fact:
|
set_fact:
|
||||||
ldap_component_id: "{{ (ldap_components.stdout | from_json)[0].id }}"
|
ldap_component_id: "{{ (ldap_components.stdout | from_json)[0].id }}"
|
||||||
|
|
||||||
- name: Ensure {{ ldap.attributes.ssh_public_key }} LDAP Mapper exists
|
- name: Ensure {{ ldap.user.attributes.ssh_public_key }} LDAP Mapper exists
|
||||||
shell: |
|
shell: |
|
||||||
docker exec -i keycloak_application bash -c '
|
docker exec -i keycloak_application bash -c '
|
||||||
/opt/keycloak/bin/kcadm.sh get components -r {{ keycloak_realm }} \
|
/opt/keycloak/bin/kcadm.sh get components -r {{ keycloak_realm }} \
|
||||||
| grep -q "\"name\" : \"{{ ldap.attributes.ssh_public_key }}\"" \
|
| grep -q "\"name\" : \"{{ ldap.user.attributes.ssh_public_key }}\"" \
|
||||||
|| printf "%s\n" "{
|
|| printf "%s\n" "{
|
||||||
\"name\": \"{{ ldap.attributes.ssh_public_key }}\",
|
\"name\": \"{{ ldap.user.attributes.ssh_public_key }}\",
|
||||||
\"parentId\": \"{{ ldap_component_id }}\",
|
\"parentId\": \"{{ ldap_component_id }}\",
|
||||||
\"providerId\": \"user-attribute-ldap-mapper\",
|
\"providerId\": \"user-attribute-ldap-mapper\",
|
||||||
\"providerType\": \"org.keycloak.storage.ldap.mappers.LDAPStorageMapper\",
|
\"providerType\": \"org.keycloak.storage.ldap.mappers.LDAPStorageMapper\",
|
||||||
\"config\": {
|
\"config\": {
|
||||||
\"user.model.attribute\": [\"{{ ldap.attributes.ssh_public_key }}\"],
|
\"user.model.attribute\": [\"{{ ldap.user.attributes.ssh_public_key }}\"],
|
||||||
\"ldap.attribute\": [\"{{ ldap.attributes.ssh_public_key }}\"],
|
\"ldap.attribute\": [\"{{ ldap.user.attributes.ssh_public_key }}\"],
|
||||||
\"read.only\": [\"false\"],
|
\"read.only\": [\"false\"],
|
||||||
\"write.only\": [\"true\"],
|
\"write.only\": [\"true\"],
|
||||||
\"always.read.value.from.ldap\": [\"false\"],
|
\"always.read.value.from.ldap\": [\"false\"],
|
||||||
|
@@ -885,12 +885,14 @@
|
|||||||
"email"
|
"email"
|
||||||
],
|
],
|
||||||
"optionalClientScopes": [
|
"optionalClientScopes": [
|
||||||
"nextcloud",
|
|
||||||
"address",
|
"address",
|
||||||
"phone",
|
"phone",
|
||||||
"organization",
|
"organization",
|
||||||
"offline_access",
|
"offline_access",
|
||||||
"microprofile-jwt"
|
"microprofile-jwt",
|
||||||
|
"{{ applications[application_id]scopes.rbac_roles }}",
|
||||||
|
"{{ applications[application_id]scopes.nextcloud }}"
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -1195,7 +1197,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "15dd4961-5b4f-4635-a3f1-a21e1fa7bf3a",
|
"id": "15dd4961-5b4f-4635-a3f1-a21e1fa7bf3a",
|
||||||
"name": "nextcloud",
|
"name": "{{ applications[application_id]scopes.nextcloud }}",
|
||||||
"description": "Optimized mappers for nextcloud oidc_login with ldap.",
|
"description": "Optimized mappers for nextcloud oidc_login with ldap.",
|
||||||
"protocol": "openid-connect",
|
"protocol": "openid-connect",
|
||||||
"attributes": {
|
"attributes": {
|
||||||
@@ -1207,7 +1209,7 @@
|
|||||||
"protocolMappers": [
|
"protocolMappers": [
|
||||||
{
|
{
|
||||||
"id": "62190b21-f649-4aa2-806a-2bf7ba103ce1",
|
"id": "62190b21-f649-4aa2-806a-2bf7ba103ce1",
|
||||||
"name": "nextcloudQuota",
|
"name": "{{ ldap.user.attributes.nextcloud_quota }}",
|
||||||
"protocol": "openid-connect",
|
"protocol": "openid-connect",
|
||||||
"protocolMapper": "oidc-usermodel-attribute-mapper",
|
"protocolMapper": "oidc-usermodel-attribute-mapper",
|
||||||
"consentRequired": false,
|
"consentRequired": false,
|
||||||
@@ -1216,11 +1218,11 @@
|
|||||||
"introspection.token.claim": "true",
|
"introspection.token.claim": "true",
|
||||||
"multivalued": "false",
|
"multivalued": "false",
|
||||||
"userinfo.token.claim": "true",
|
"userinfo.token.claim": "true",
|
||||||
"user.attribute": "nextcloudQuota",
|
"user.attribute": "{{ ldap.user.attributes.nextcloud_quota }}",
|
||||||
"id.token.claim": "true",
|
"id.token.claim": "true",
|
||||||
"lightweight.claim": "false",
|
"lightweight.claim": "false",
|
||||||
"access.token.claim": "true",
|
"access.token.claim": "true",
|
||||||
"claim.name": "nextcloudQuota",
|
"claim.name": "{{ ldap.user.attributes.nextcloud_quota }}",
|
||||||
"jsonType.label": "int"
|
"jsonType.label": "int"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1239,12 +1241,43 @@
|
|||||||
"id.token.claim": "true",
|
"id.token.claim": "true",
|
||||||
"lightweight.claim": "false",
|
"lightweight.claim": "false",
|
||||||
"access.token.claim": "true",
|
"access.token.claim": "true",
|
||||||
"claim.name": "{{ldap.attributes.user_id}}",
|
"claim.name": "{{ldap.user.attributes.id}}",
|
||||||
"jsonType.label": "String"
|
"jsonType.label": "String"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "59917c48-a7ef-464a-a8b0-ea24316db18e",
|
||||||
|
"name": "{{ applications[application_id]scopes.rbac_roles }}",
|
||||||
|
"description": "RBAC Groups",
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"attributes": {
|
||||||
|
"include.in.token.scope": "false",
|
||||||
|
"display.on.consent.screen": "true",
|
||||||
|
"gui.order": "",
|
||||||
|
"consent.screen.text": ""
|
||||||
|
},
|
||||||
|
"protocolMappers": [
|
||||||
|
{
|
||||||
|
"id": "0388cdf9-4751-484a-956c-431dbd872578",
|
||||||
|
"name": "groups",
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"protocolMapper": "oidc-group-membership-mapper",
|
||||||
|
"consentRequired": false,
|
||||||
|
"config": {
|
||||||
|
"full.path": "true",
|
||||||
|
"introspection.token.claim": "true",
|
||||||
|
"userinfo.token.claim": "true",
|
||||||
|
"multivalued": "true",
|
||||||
|
"id.token.claim": "true",
|
||||||
|
"lightweight.claim": "false",
|
||||||
|
"access.token.claim": "true",
|
||||||
|
"claim.name": "{{ oidc.claims.groups }}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "c07f07bc-c4f9-48c7-87e6-0a09fca6bfa0",
|
"id": "c07f07bc-c4f9-48c7-87e6-0a09fca6bfa0",
|
||||||
"name": "web-origins",
|
"name": "web-origins",
|
||||||
@@ -1637,12 +1670,13 @@
|
|||||||
"basic"
|
"basic"
|
||||||
],
|
],
|
||||||
"defaultOptionalClientScopes": [
|
"defaultOptionalClientScopes": [
|
||||||
"nextcloud",
|
|
||||||
"offline_access",
|
"offline_access",
|
||||||
"address",
|
"address",
|
||||||
"phone",
|
"phone",
|
||||||
"microprofile-jwt",
|
"microprofile-jwt",
|
||||||
"organization"
|
"organization",
|
||||||
|
"{{ applications[application_id]scopes.rbac_roles }}",
|
||||||
|
"{{ applications[application_id]scopes.nextcloud }}"
|
||||||
],
|
],
|
||||||
"browserSecurityHeaders": {
|
"browserSecurityHeaders": {
|
||||||
"contentSecurityPolicyReportOnly": "",
|
"contentSecurityPolicyReportOnly": "",
|
||||||
@@ -1792,7 +1826,7 @@
|
|||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"kc.user.profile.config": [
|
"kc.user.profile.config": [
|
||||||
"{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"pattern\":{\"pattern\":\"^[a-z0-9]+$\",\"error-message\":\"\"}},\"annotations\":{},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"{{ ldap.attributes.ssh_public_key }}\",\"displayName\":\"SSH Public Key\",\"validations\":{},\"annotations\":{},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"group\":\"user-metadata\",\"multivalued\":true}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}"
|
"{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"pattern\":{\"pattern\":\"^[a-z0-9]+$\",\"error-message\":\"\"}},\"annotations\":{},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"{{ ldap.user.attributes.ssh_public_key }}\",\"displayName\":\"SSH Public Key\",\"validations\":{},\"annotations\":{},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"group\":\"user-metadata\",\"multivalued\":true}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1858,12 +1892,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "12b99578-e0bf-4eeb-b0fb-8e400c0cd73e",
|
"id": "12b99578-e0bf-4eeb-b0fb-8e400c0cd73e",
|
||||||
"name": "nextcloudQuota",
|
"name": "{{ ldap.user.attributes.nextcloud_quota }}",
|
||||||
"providerId": "user-attribute-ldap-mapper",
|
"providerId": "user-attribute-ldap-mapper",
|
||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"ldap.attribute": [
|
"ldap.attribute": [
|
||||||
"nextcloudQuota"
|
"{{ ldap.user.attributes.nextcloud_quota }}"
|
||||||
],
|
],
|
||||||
"is.mandatory.in.ldap": [
|
"is.mandatory.in.ldap": [
|
||||||
"false"
|
"false"
|
||||||
@@ -1881,7 +1915,86 @@
|
|||||||
"false"
|
"false"
|
||||||
],
|
],
|
||||||
"user.model.attribute": [
|
"user.model.attribute": [
|
||||||
"nextcloudQuota"
|
"{{ ldap.user.attributes.nextcloud_quota }}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "24cd9c3b-e22d-4540-bddf-ae7faac0196c",
|
||||||
|
"name": "SSH Public Key",
|
||||||
|
"providerId": "user-attribute-ldap-mapper",
|
||||||
|
"subComponents": {},
|
||||||
|
"config": {
|
||||||
|
"ldap.attribute": [
|
||||||
|
"{{ ldap.user.attributes.ssh_public_key }}"
|
||||||
|
],
|
||||||
|
"is.mandatory.in.ldap": [
|
||||||
|
"false"
|
||||||
|
],
|
||||||
|
"attribute.force.default": [
|
||||||
|
"false"
|
||||||
|
],
|
||||||
|
"is.binary.attribute": [
|
||||||
|
"false"
|
||||||
|
],
|
||||||
|
"read.only": [
|
||||||
|
"false"
|
||||||
|
],
|
||||||
|
"always.read.value.from.ldap": [
|
||||||
|
"true"
|
||||||
|
],
|
||||||
|
"user.model.attribute": [
|
||||||
|
"{{ ldap.user.attributes.ssh_public_key }}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "f56e4551-c5b5-4596-b567-bc8309a74e72",
|
||||||
|
"name": "ldap-roles",
|
||||||
|
"providerId": "group-ldap-mapper",
|
||||||
|
"subComponents": {},
|
||||||
|
"config": {
|
||||||
|
"membership.attribute.type": [
|
||||||
|
"DN"
|
||||||
|
],
|
||||||
|
"group.name.ldap.attribute": [
|
||||||
|
"{{ ldap.user.attributes.fullname }}"
|
||||||
|
],
|
||||||
|
"membership.user.ldap.attribute": [
|
||||||
|
"{{ ldap.user.attributes.id }}"
|
||||||
|
],
|
||||||
|
"preserve.group.inheritance": [
|
||||||
|
"false"
|
||||||
|
],
|
||||||
|
"groups.dn": [
|
||||||
|
"{{ ldap.dn.ou.roles }}"
|
||||||
|
],
|
||||||
|
"mode": [
|
||||||
|
"LDAP_ONLY"
|
||||||
|
],
|
||||||
|
"user.roles.retrieve.strategy": [
|
||||||
|
"LOAD_GROUPS_BY_MEMBER_ATTRIBUTE"
|
||||||
|
],
|
||||||
|
"groups.ldap.filter": [
|
||||||
|
"(objectClass=groupOfNames)"
|
||||||
|
],
|
||||||
|
"membership.ldap.attribute": [
|
||||||
|
"member"
|
||||||
|
],
|
||||||
|
"ignore.missing.groups": [
|
||||||
|
"true"
|
||||||
|
],
|
||||||
|
"group.object.classes": [
|
||||||
|
"groupOfNames"
|
||||||
|
],
|
||||||
|
"memberof.ldap.attribute": [
|
||||||
|
"memberOf"
|
||||||
|
],
|
||||||
|
"drop.non.existing.groups.during.sync": [
|
||||||
|
"false"
|
||||||
|
],
|
||||||
|
"groups.path": [
|
||||||
|
"{{ applications[application_id].rbac_groups }}"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1944,7 +2057,7 @@
|
|||||||
"true"
|
"true"
|
||||||
],
|
],
|
||||||
"ldap.full.name.attribute": [
|
"ldap.full.name.attribute": [
|
||||||
"{{ ldap.attributes.fullname }}"
|
"{{ ldap.user.attributes.fullname }}"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1955,7 +2068,7 @@
|
|||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"ldap.attribute": [
|
"ldap.attribute": [
|
||||||
"{{ldap.attributes.user_id}}"
|
"{{ldap.user.attributes.id}}"
|
||||||
],
|
],
|
||||||
"is.mandatory.in.ldap": [
|
"is.mandatory.in.ldap": [
|
||||||
"true"
|
"true"
|
||||||
@@ -1984,7 +2097,7 @@
|
|||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"ldap.attribute": [
|
"ldap.attribute": [
|
||||||
"{{ ldap.attributes.ssh_public_key }}"
|
"{{ ldap.user.attributes.ssh_public_key }}"
|
||||||
],
|
],
|
||||||
"is.mandatory.in.ldap": [
|
"is.mandatory.in.ldap": [
|
||||||
"false"
|
"false"
|
||||||
@@ -2002,7 +2115,7 @@
|
|||||||
"true"
|
"true"
|
||||||
],
|
],
|
||||||
"user.model.attribute": [
|
"user.model.attribute": [
|
||||||
"{{ ldap.attributes.ssh_public_key }}"
|
"{{ ldap.user.attributes.ssh_public_key }}"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2069,7 +2182,7 @@
|
|||||||
"-1"
|
"-1"
|
||||||
],
|
],
|
||||||
"usernameLDAPAttribute": [
|
"usernameLDAPAttribute": [
|
||||||
"{{ldap.attributes.user_id}}"
|
"{{ldap.user.attributes.id}}"
|
||||||
],
|
],
|
||||||
"bindDn": [
|
"bindDn": [
|
||||||
"{{ldap.dn.administrator.data}}"
|
"{{ldap.dn.administrator.data}}"
|
||||||
@@ -2081,7 +2194,7 @@
|
|||||||
"other"
|
"other"
|
||||||
],
|
],
|
||||||
"uuidLDAPAttribute": [
|
"uuidLDAPAttribute": [
|
||||||
"{{ldap.attributes.user_id}}"
|
"{{ldap.user.attributes.id}}"
|
||||||
],
|
],
|
||||||
"allowKerberosAuthentication": [
|
"allowKerberosAuthentication": [
|
||||||
"false"
|
"false"
|
||||||
@@ -2111,10 +2224,10 @@
|
|||||||
"false"
|
"false"
|
||||||
],
|
],
|
||||||
"userObjectClasses": [
|
"userObjectClasses": [
|
||||||
"{{ ldap.user_objects | join(', ') }}"
|
"{{ ldap.user.objects | join(', ') }}"
|
||||||
],
|
],
|
||||||
"rdnLDAPAttribute": [
|
"rdnLDAPAttribute": [
|
||||||
"{{ldap.attributes.user_id}}"
|
"{{ldap.user.attributes.id}}"
|
||||||
],
|
],
|
||||||
"editMode": [
|
"editMode": [
|
||||||
"WRITABLE"
|
"WRITABLE"
|
||||||
|
@@ -19,4 +19,9 @@ csp:
|
|||||||
unsafe-inline: true
|
unsafe-inline: true
|
||||||
domains:
|
domains:
|
||||||
canonical:
|
canonical:
|
||||||
- "auth.{{ primary_domain }}"
|
- "auth.{{ primary_domain }}"
|
||||||
|
scopes:
|
||||||
|
rbac_roles: rbac_roles
|
||||||
|
nextcloud: nextcloud
|
||||||
|
|
||||||
|
rbac_groups: "/rbac"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
# Todos
|
# Todos
|
||||||
- Implement auto memberof setup
|
- User Groups and Roles on the proper way
|
||||||
- Create a Dockerfile (may in an own repository) with memberOf
|
- Refactor the use of groups as roles in oauth2 proxy
|
||||||
- Find a better decoupling solution for nextcloud
|
|
@@ -35,7 +35,11 @@ docker exec -it ldap ldapsearch -Y EXTERNAL -H ldapi:/// -b "cn=config" "(olcDat
|
|||||||
To execute the following commands set the credentials via:
|
To execute the following commands set the credentials via:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export $(grep -Ev '^(#|$)' .env/env | xargs)
|
eval $(
|
||||||
|
grep -v '^\s*#' .env/env \
|
||||||
|
| sed -E 's/\s*#.*//' \
|
||||||
|
| sed -E 's/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/export \1="\2"/'
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Show all Entries
|
### Show all Entries
|
||||||
|
@@ -0,0 +1,77 @@
|
|||||||
|
def build_ldap_nested_group_entries(applications, users, ldap):
|
||||||
|
"""
|
||||||
|
Builds structured LDAP role entries using the global `ldap` configuration.
|
||||||
|
Supports objectClasses: posixGroup (adds gidNumber, memberUid), groupOfNames (adds member).
|
||||||
|
Now nests roles under an application-level OU: application-id/role.
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
# Base DN components
|
||||||
|
role_dn_base = ldap["dn"]["ou"]["roles"]
|
||||||
|
user_dn_base = ldap["dn"]["ou"]["users"]
|
||||||
|
ldap_user_attr = ldap["user"]["attributes"]["id"]
|
||||||
|
|
||||||
|
# Supported objectClass flavors
|
||||||
|
flavors = ldap.get("rbac", {}).get("flavors", [])
|
||||||
|
|
||||||
|
for application_id, app_config in applications.items():
|
||||||
|
# Compute the DN for the application-level OU
|
||||||
|
app_ou_dn = f"ou={application_id},{role_dn_base}"
|
||||||
|
|
||||||
|
ou_entry = {
|
||||||
|
"dn": app_ou_dn,
|
||||||
|
"objectClass": ["top", "organizationalUnit"],
|
||||||
|
"ou": application_id,
|
||||||
|
"description": f"Roles for application {application_id}"
|
||||||
|
}
|
||||||
|
result[app_ou_dn] = ou_entry
|
||||||
|
|
||||||
|
# Standard roles with an extra 'administrator'
|
||||||
|
base_roles = app_config.get("rbac", {}).get("roles", {})
|
||||||
|
roles = {
|
||||||
|
**base_roles,
|
||||||
|
"administrator": {
|
||||||
|
"description": "Has full administrative access: manage themes, plugins, settings, and users"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
group_id = app_config.get("group_id")
|
||||||
|
|
||||||
|
for role_name, role_conf in roles.items():
|
||||||
|
# Build CN under the application OU
|
||||||
|
cn = role_name
|
||||||
|
dn = f"cn={cn},{app_ou_dn}"
|
||||||
|
|
||||||
|
entry = {
|
||||||
|
"dn": dn,
|
||||||
|
"cn": cn,
|
||||||
|
"description": role_conf.get("description", ""),
|
||||||
|
"objectClass": ["top"] + flavors,
|
||||||
|
}
|
||||||
|
|
||||||
|
member_dns = []
|
||||||
|
member_uids = []
|
||||||
|
for username, user_conf in users.items():
|
||||||
|
if role_name in user_conf.get("roles", []):
|
||||||
|
member_dns.append(f"{ldap_user_attr}={username},{user_dn_base}")
|
||||||
|
member_uids.append(username)
|
||||||
|
|
||||||
|
if "posixGroup" in flavors:
|
||||||
|
entry["gidNumber"] = group_id
|
||||||
|
if member_uids:
|
||||||
|
entry["memberUid"] = member_uids
|
||||||
|
|
||||||
|
if "groupOfNames" in flavors and member_dns:
|
||||||
|
entry["member"] = member_dns
|
||||||
|
|
||||||
|
result[dn] = entry
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class FilterModule(object):
|
||||||
|
def filters(self):
|
||||||
|
return {
|
||||||
|
"build_ldap_nested_group_entries": build_ldap_nested_group_entries
|
||||||
|
}
|
@@ -9,7 +9,7 @@
|
|||||||
attrs:
|
attrs:
|
||||||
- dn
|
- dn
|
||||||
- objectClass
|
- objectClass
|
||||||
- "{{ ldap.attributes.user_id }}"
|
- "{{ ldap.user.attributes.id }}"
|
||||||
register: ldap_users_with_classes
|
register: ldap_users_with_classes
|
||||||
|
|
||||||
- name: Add only missing auxiliary classes
|
- name: Add only missing auxiliary classes
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
label: "{{ item.dn }}"
|
label: "{{ item.dn }}"
|
||||||
vars:
|
vars:
|
||||||
missing_auxiliary: >-
|
missing_auxiliary: >-
|
||||||
{{ ldap.user_objects.auxiliary
|
{{ (ldap.user.objects.auxiliary.values() | list)
|
||||||
| difference(item.objectClass | default([]))
|
| difference(item.objectClass | default([]))
|
||||||
}}
|
}}
|
||||||
when: missing_auxiliary | length > 0
|
when: missing_auxiliary | length > 0
|
||||||
|
@@ -63,11 +63,11 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
- name: Ensure LDAP users exist
|
- name: Ensure LDAP users exist
|
||||||
community.general.ldap_entry:
|
community.general.ldap_entry:
|
||||||
dn: "{{ ldap.attributes.user_id }}={{ item.key }},{{ ldap.dn.ou.users }}"
|
dn: "{{ ldap.user.attributes.id }}={{ item.key }},{{ ldap.dn.ou.users }}"
|
||||||
server_uri: "{{ ldap_server_uri }}"
|
server_uri: "{{ ldap_server_uri }}"
|
||||||
bind_dn: "{{ ldap.dn.administrator.data }}"
|
bind_dn: "{{ ldap.dn.administrator.data }}"
|
||||||
bind_pw: "{{ ldap.bind_credential }}"
|
bind_pw: "{{ ldap.bind_credential }}"
|
||||||
objectClass: "{{ ldap.user_objects.structural }}"
|
objectClass: "{{ ldap.user.objects.structural }}"
|
||||||
attributes:
|
attributes:
|
||||||
uid: "{{ item.value.username }}"
|
uid: "{{ item.value.username }}"
|
||||||
sn: "{{ item.value.sn | default(item.key) }}"
|
sn: "{{ item.value.sn | default(item.key) }}"
|
||||||
@@ -89,12 +89,12 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
- name: Ensure required objectClass values and mail address are present
|
- name: Ensure required objectClass values and mail address are present
|
||||||
community.general.ldap_attrs:
|
community.general.ldap_attrs:
|
||||||
dn: "{{ ldap.attributes.user_id }}={{ item.key }},{{ ldap.dn.ou.users }}"
|
dn: "{{ ldap.user.attributes.id }}={{ item.key }},{{ ldap.dn.ou.users }}"
|
||||||
server_uri: "{{ ldap_server_uri }}"
|
server_uri: "{{ ldap_server_uri }}"
|
||||||
bind_dn: "{{ ldap.dn.administrator.data }}"
|
bind_dn: "{{ ldap.dn.administrator.data }}"
|
||||||
bind_pw: "{{ ldap.bind_credential }}"
|
bind_pw: "{{ ldap.bind_credential }}"
|
||||||
attributes:
|
attributes:
|
||||||
objectClass: "{{ ldap.user_objects.structural }}"
|
objectClass: "{{ ldap.user.objects.structural }}"
|
||||||
mail: "{{ item.value.email }}"
|
mail: "{{ item.value.email }}"
|
||||||
state: exact
|
state: exact
|
||||||
async: 60
|
async: 60
|
||||||
|
@@ -8,9 +8,9 @@
|
|||||||
vars:
|
vars:
|
||||||
schema_name: "nextcloud"
|
schema_name: "nextcloud"
|
||||||
attribute_defs:
|
attribute_defs:
|
||||||
- "( 1.3.6.1.4.1.99999.1 NAME 'nextcloudQuota' DESC 'Quota for Nextcloud' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )"
|
- "( 1.3.6.1.4.1.99999.1 NAME '{{ ldap.user.attributes.nextcloud_quota }}' DESC 'Quota for Nextcloud' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )"
|
||||||
objectclass_defs:
|
objectclass_defs:
|
||||||
- "( 1.3.6.1.4.1.99999.2 NAME 'nextcloudUser' DESC 'Auxiliary class for Nextcloud attributes' AUXILIARY MAY ( nextcloudQuota ) )"
|
- "( 1.3.6.1.4.1.99999.2 NAME 'nextcloudUser' DESC 'Auxiliary class for Nextcloud attributes' AUXILIARY MAY ( {{ ldap.user.attributes.nextcloud_quota }} ) )"
|
||||||
command: >
|
command: >
|
||||||
ldapsm
|
ldapsm
|
||||||
-s {{ ldap_server_uri }}
|
-s {{ ldap_server_uri }}
|
||||||
|
@@ -8,16 +8,16 @@
|
|||||||
vars:
|
vars:
|
||||||
schema_name: "openssh-lpk"
|
schema_name: "openssh-lpk"
|
||||||
attribute_defs:
|
attribute_defs:
|
||||||
- "( 1.3.6.1.4.1.24552.1.1 NAME '{{ ldap.attributes.ssh_public_key }}' DESC 'OpenSSH Public Key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )"
|
- "( 1.3.6.1.4.1.24552.1.1 NAME '{{ ldap.user.attributes.ssh_public_key }}' DESC 'OpenSSH Public Key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )"
|
||||||
- "( 1.3.6.1.4.1.24552.1.2 NAME 'sshFingerprint' DESC 'OpenSSH Public Key Fingerprint' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )"
|
- "( 1.3.6.1.4.1.24552.1.2 NAME 'sshFingerprint' DESC 'OpenSSH Public Key Fingerprint' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )"
|
||||||
objectclass_defs:
|
objectclass_defs:
|
||||||
- >-
|
- >-
|
||||||
( 1.3.6.1.4.1.24552.2.1
|
( 1.3.6.1.4.1.24552.2.1
|
||||||
NAME 'ldapPublicKey'
|
NAME '{{ ldap.user.objects.auxiliary.ssh_public_key }}'
|
||||||
DESC 'Auxiliary class for OpenSSH public keys'
|
DESC 'Auxiliary class for OpenSSH public keys'
|
||||||
SUP top
|
SUP top
|
||||||
AUXILIARY
|
AUXILIARY
|
||||||
MAY ( {{ ldap.attributes.ssh_public_key }} $ sshFingerprint ) )
|
MAY ( {{ ldap.user.attributes.ssh_public_key }} $ sshFingerprint ) )
|
||||||
|
|
||||||
command: >
|
command: >
|
||||||
ldapsm
|
ldapsm
|
||||||
|
30
roles/docker-ldap/templates/ldif/data/01_rbac_group.ldif.j2
Normal file
30
roles/docker-ldap/templates/ldif/data/01_rbac_group.ldif.j2
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{#
|
||||||
|
@todo: activate
|
||||||
|
{% for dn, entry in (applications | build_ldap_role_entries(users, ldap)).items() %}
|
||||||
|
|
||||||
|
dn: {{ dn }}
|
||||||
|
{% for oc in entry.objectClass %}
|
||||||
|
objectClass: {{ oc }}
|
||||||
|
{% endfor %}
|
||||||
|
{% if entry.ou is defined %}
|
||||||
|
ou: {{ entry.ou }}
|
||||||
|
{% else %}
|
||||||
|
cn: {{ entry.cn }}
|
||||||
|
{% endif %}
|
||||||
|
{% if entry.gidNumber is defined %}
|
||||||
|
gidNumber: {{ entry.gidNumber }}
|
||||||
|
{% endif %}
|
||||||
|
description: {{ entry.description }}
|
||||||
|
{% if entry.memberUid is defined %}
|
||||||
|
{% for uid in entry.memberUid %}
|
||||||
|
memberUid: {{ uid }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if entry.member is defined %}
|
||||||
|
{% for m in entry.member %}
|
||||||
|
member: {{ m }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
#}
|
@@ -97,10 +97,10 @@ return array (
|
|||||||
// note: on Keycloak, OIDC name claim = "${given_name} ${family_name}" or one of them if any is missing
|
// note: on Keycloak, OIDC name claim = "${given_name} ${family_name}" or one of them if any is missing
|
||||||
//
|
//
|
||||||
'oidc_login_attributes' => array (
|
'oidc_login_attributes' => array (
|
||||||
'id' => '{{ldap.attributes.user_id}}',
|
'id' => '{{ldap.user.attributes.id}}',
|
||||||
'name' => 'name',
|
'name' => 'name',
|
||||||
'mail' => 'email',
|
'mail' => 'email',
|
||||||
'quota' => 'nextcloudQuota',
|
'quota' => '{{ ldap.user.attributes.nextcloud_quota }}',
|
||||||
# 'home' => 'homeDirectory', # Not implemented yet
|
# 'home' => 'homeDirectory', # Not implemented yet
|
||||||
'ldap_uid' => '{{oidc.attributes.username}}',
|
'ldap_uid' => '{{oidc.attributes.username}}',
|
||||||
# 'groups' => 'ownCloudGroups', # Not implemented yet
|
# 'groups' => 'ownCloudGroups', # Not implemented yet
|
||||||
|
@@ -181,4 +181,4 @@ plugin_configuration:
|
|||||||
-
|
-
|
||||||
appid: "user_ldap"
|
appid: "user_ldap"
|
||||||
configkey: "s01ldap_expert_username_attr"
|
configkey: "s01ldap_expert_username_attr"
|
||||||
configvalue: "{{ldap.attributes.user_id}}"
|
configvalue: "{{ldap.user.attributes.id}}"
|
@@ -11,13 +11,14 @@ client_id = "{{ oidc.client.id }}"
|
|||||||
redirect_url = "{{ web_protocol }}://{{ domains | get_domain(oauth2_proxy_application_id) }}/oauth2/callback"
|
redirect_url = "{{ web_protocol }}://{{ domains | get_domain(oauth2_proxy_application_id) }}/oauth2/callback"
|
||||||
oidc_issuer_url = "{{ oidc.client.issuer_url }}"
|
oidc_issuer_url = "{{ oidc.client.issuer_url }}"
|
||||||
provider = "oidc"
|
provider = "oidc"
|
||||||
provider_display_name = "Keycloak"
|
provider_display_name = "{{ oidc.button_text }}"
|
||||||
|
|
||||||
{% if applications[oauth2_proxy_application_id].oauth2_proxy.allowed_groups is defined %}
|
{% if applications[oauth2_proxy_application_id].oauth2_proxy.allowed_groups is defined %}
|
||||||
{# role based restrictions #}
|
{# role based restrictions #}
|
||||||
scope = "openid email profile groups"
|
scope = "openid email profile {{ oidc.claims.groups }}"
|
||||||
oidc_groups_claim = "realm_access.roles"
|
oidc_groups_claim = "{{ oidc.claims.groups }}"
|
||||||
allowed_groups = {{ applications[oauth2_proxy_application_id].oauth2_proxy.allowed_groups | tojson }}
|
allowed_groups = {{ applications[oauth2_proxy_application_id].oauth2_proxy.allowed_groups | tojson }}
|
||||||
|
email_domains = ["*"]
|
||||||
{% else %}
|
{% else %}
|
||||||
email_domains = "{{ primary_domain }}"
|
email_domains = "{{ primary_domain }}"
|
||||||
{% endif %}
|
{% endif %}
|
@@ -5,10 +5,10 @@ openproject_ldap:
|
|||||||
account: "{{ ldap.dn.administrator.data }}" # Bind DN (used for authentication)
|
account: "{{ ldap.dn.administrator.data }}" # Bind DN (used for authentication)
|
||||||
account_password: "{{ ldap.bind_credential }}" # Bind password
|
account_password: "{{ ldap.bind_credential }}" # Bind password
|
||||||
base_dn: "{{ ldap.dn.ou.users }}" # Base DN for user search
|
base_dn: "{{ ldap.dn.ou.users }}" # Base DN for user search
|
||||||
attr_login: "{{ ldap.attributes.user_id }}" # LDAP attribute used for login
|
attr_login: "{{ ldap.user.attributes.id }}" # LDAP attribute used for login
|
||||||
attr_firstname: "givenName" # LDAP attribute for first name
|
attr_firstname: "givenName" # LDAP attribute for first name
|
||||||
attr_lastname: "{{ ldap.attributes.surname }}" # LDAP attribute for last name
|
attr_lastname: "{{ ldap.user.attributes.surname }}" # LDAP attribute for last name
|
||||||
attr_mail: "{{ ldap.attributes.mail }}" # LDAP attribute for email
|
attr_mail: "{{ ldap.user.attributes.mail }}" # LDAP attribute for email
|
||||||
attr_admin: "{{ openproject_filters.administrators }}" # Optional: LDAP attribute for admin group (leave empty if unused)
|
attr_admin: "{{ openproject_filters.administrators }}" # Optional: LDAP attribute for admin group (leave empty if unused)
|
||||||
onthefly_register: true # Automatically create users on first login
|
onthefly_register: true # Automatically create users on first login
|
||||||
tls_mode: 0 # 0 = No TLS, 1 = TLS, 2 = STARTTLS
|
tls_mode: 0 # 0 = No TLS, 1 = TLS, 2 = STARTTLS
|
||||||
|
@@ -12,6 +12,8 @@ portfolio_menu_categories:
|
|||||||
- listmonk
|
- listmonk
|
||||||
- moodle
|
- moodle
|
||||||
- mybb
|
- mybb
|
||||||
|
- mobilizon
|
||||||
|
- friendica
|
||||||
|
|
||||||
Project Management:
|
Project Management:
|
||||||
description: "Project Management Tools"
|
description: "Project Management Tools"
|
||||||
@@ -39,6 +41,7 @@ portfolio_menu_categories:
|
|||||||
- mastodon
|
- mastodon
|
||||||
- peertube
|
- peertube
|
||||||
- pixelfed
|
- pixelfed
|
||||||
|
- friendica
|
||||||
|
|
||||||
Communication:
|
Communication:
|
||||||
description: "Tools for communication"
|
description: "Tools for communication"
|
||||||
@@ -78,7 +81,6 @@ portfolio_menu_categories:
|
|||||||
- fusiondirectory
|
- fusiondirectory
|
||||||
- user-management
|
- user-management
|
||||||
|
|
||||||
|
|
||||||
Server Administration:
|
Server Administration:
|
||||||
description: "Administration Tools für servers"
|
description: "Administration Tools für servers"
|
||||||
icon: "fas fa-building"
|
icon: "fas fa-building"
|
||||||
@@ -102,12 +104,18 @@ portfolio_menu_categories:
|
|||||||
- utility
|
- utility
|
||||||
- baserow
|
- baserow
|
||||||
- compose
|
- compose
|
||||||
- presentation
|
|
||||||
- repository-setup
|
- repository-setup
|
||||||
- roulette-wheel
|
- roulette-wheel
|
||||||
- sphinx
|
|
||||||
- yourls
|
- yourls
|
||||||
|
|
||||||
|
Presentation:
|
||||||
|
description: "Presentation and Documentation Tools"
|
||||||
|
icon: "fas fa-tools"
|
||||||
|
tags:
|
||||||
|
- presentation
|
||||||
|
- sphinx
|
||||||
|
- portfolio
|
||||||
|
|
||||||
Finance & Accounting:
|
Finance & Accounting:
|
||||||
description: "Financial and accounting software"
|
description: "Financial and accounting software"
|
||||||
icon: "fa-solid fa-dollar-sign"
|
icon: "fa-solid fa-dollar-sign"
|
||||||
|
2
roles/docker-postmarks/Todo.md
Normal file
2
roles/docker-postmarks/Todo.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Todo
|
||||||
|
- Implement https://github.com/ckolderup/postmarks
|
1
roles/docker-postmarks/vars/main.yml
Normal file
1
roles/docker-postmarks/vars/main.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
application_id: postmarks
|
@@ -47,16 +47,16 @@
|
|||||||
$s->ldap_uname = "{{ ldap.dn.administrator.data }}";
|
$s->ldap_uname = "{{ ldap.dn.administrator.data }}";
|
||||||
$s->ldap_basedn = "{{ ldap.dn.ou.users }}";
|
$s->ldap_basedn = "{{ ldap.dn.ou.users }}";
|
||||||
$s->ldap_filter = "&(objectClass=inetOrgPerson)";
|
$s->ldap_filter = "&(objectClass=inetOrgPerson)";
|
||||||
$s->ldap_username_field = "{{ ldap.attributes.user_id }}";
|
$s->ldap_username_field = "{{ ldap.user.attributes.id }}";
|
||||||
$s->ldap_fname_field = "{{ ldap.attributes.firstname }}";
|
$s->ldap_fname_field = "{{ ldap.user.attributes.firstname }}";
|
||||||
$s->ldap_lname_field = "{{ ldap.attributes.surname }}";
|
$s->ldap_lname_field = "{{ ldap.user.attributes.surname }}";
|
||||||
$s->ldap_auth_filter_query = "uid=";
|
$s->ldap_auth_filter_query = "uid=";
|
||||||
$s->ldap_version = 3;
|
$s->ldap_version = 3;
|
||||||
$s->ldap_pw_sync = 0;
|
$s->ldap_pw_sync = 0;
|
||||||
$s->is_ad = 0;
|
$s->is_ad = 0;
|
||||||
$s->ad_domain = "";
|
$s->ad_domain = "";
|
||||||
$s->ldap_default_group = "";
|
$s->ldap_default_group = "";
|
||||||
$s->ldap_email = "{{ ldap.attributes.mail }}";
|
$s->ldap_email = "{{ ldap.user.attributes.mail }}";
|
||||||
$s->custom_forgot_pass_url = "{{ oidc.client.reset_credentials }}";
|
$s->custom_forgot_pass_url = "{{ oidc.client.reset_credentials }}";
|
||||||
$s->save();
|
$s->save();
|
||||||
EOF'
|
EOF'
|
||||||
|
2
roles/docker-socialhome/Todo.md
Normal file
2
roles/docker-socialhome/Todo.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Todo
|
||||||
|
- Implement https://socialhome.network/
|
1
roles/docker-socialhome/vars/main.yml
Normal file
1
roles/docker-socialhome/vars/main.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
application_id: socialhome
|
46
tests/unit/filter_plugins/test_application_allowed.py
Normal file
46
tests/unit/filter_plugins/test_application_allowed.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import unittest
|
||||||
|
from filter_plugins.application_allowed import application_allowed
|
||||||
|
from ansible.errors import AnsibleFilterError
|
||||||
|
|
||||||
|
|
||||||
|
class TestApplicationAllowed(unittest.TestCase):
|
||||||
|
def test_application_not_in_group(self):
|
||||||
|
# application not in group_names should always return False
|
||||||
|
self.assertFalse(application_allowed('app1', ['other_group'], None))
|
||||||
|
self.assertFalse(application_allowed('app1', ['other_group'], []))
|
||||||
|
self.assertFalse(application_allowed('app1', ['other_group'], ['app1']))
|
||||||
|
|
||||||
|
def test_no_allowed_applications_allows_group_items(self):
|
||||||
|
# allowed_applications is None or empty -> allow if in group
|
||||||
|
self.assertTrue(application_allowed('app1', ['app1', 'app2'], None))
|
||||||
|
# empty list treated as no filter -> allow all in group
|
||||||
|
self.assertTrue(application_allowed('app2', ['app1', 'app2'], []))
|
||||||
|
|
||||||
|
def test_allowed_applications_list(self):
|
||||||
|
group = ['app1', 'app2', 'app3']
|
||||||
|
allowed = ['app2', 'app3']
|
||||||
|
self.assertFalse(application_allowed('app1', group, allowed))
|
||||||
|
self.assertTrue(application_allowed('app2', group, allowed))
|
||||||
|
self.assertTrue(application_allowed('app3', group, allowed))
|
||||||
|
|
||||||
|
def test_allowed_applications_wrong_type(self):
|
||||||
|
# invalid allowed_applications type
|
||||||
|
with self.assertRaises(AnsibleFilterError):
|
||||||
|
application_allowed('app1', ['app1'], allowed_applications=123)
|
||||||
|
|
||||||
|
def test_group_names_wrong_type(self):
|
||||||
|
# invalid group_names type
|
||||||
|
with self.assertRaises(AnsibleFilterError):
|
||||||
|
application_allowed(1232312, 'not_a_list', None)
|
||||||
|
|
||||||
|
def test_allowed_applications_edge_cases(self):
|
||||||
|
# whitespace-only entries do not affect result
|
||||||
|
group = ['app1']
|
||||||
|
allowed = ['app1', ' ', '']
|
||||||
|
self.assertTrue(application_allowed('app1', group, allowed))
|
||||||
|
# application in group but not listed -> false
|
||||||
|
self.assertFalse(application_allowed('app2', ['app2'], allowed))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
@@ -2,16 +2,14 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
# Add the filter_plugins directory from the docker-matrix role to the import path
|
|
||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0,
|
0,
|
||||||
os.path.abspath(
|
os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), "../../../roles/docker-matrix")
|
os.path.join(os.path.dirname(__file__), "../../../roles/docker-matrix/filter_plugins")
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
from filter_plugins.bridge_filters import filter_enabled_bridges
|
from bridge_filters import filter_enabled_bridges
|
||||||
|
|
||||||
|
|
||||||
class TestBridgeFilters(unittest.TestCase):
|
class TestBridgeFilters(unittest.TestCase):
|
||||||
def test_no_bridges_returns_empty_list(self):
|
def test_no_bridges_returns_empty_list(self):
|
||||||
|
Reference in New Issue
Block a user