Added LDAP integration for Nextcloud and optimized CSS

This commit is contained in:
Kevin Veen-Birkenbach 2025-02-24 23:53:12 +01:00
parent 6d5113b6ea
commit ab258cb6dd
10 changed files with 252 additions and 69 deletions

View File

@ -39,9 +39,11 @@ ldap:
# Defines the base Distinguished Name (DN) for the LDAP directory, constructed from the second-level domain (SLD) and top-level domain (TLD).
root: "{{_ldap_dn_base}}"
# Specifies the Distinguished Name (DN) of the LDAP administrator, combining the admin's username with the LDAP root domain.
bind: "cn={{applications.ldap.administrator_username}},{{_ldap_dn_base}}"
administrator: "cn={{applications.ldap.administrator_username}},{{_ldap_dn_base}}"
# Dn from which the users should be read
users: "ou=users,{{_ldap_dn_base}}"
# Dn from which the groups should be read
groups: "ou=groups,{{_ldap_dn_base}}"
# Dn for all application roles of the users
application_roles: "ou=application_roles,{{_ldap_dn_base}}"
# Password to access dn.bind

View File

@ -109,7 +109,7 @@ DJANGO_SECRET_KEY={{funkwhale_django_secret}}
LDAP_ENABLED = True
LDAP_SERVER_URI = "{{ldap.server.uri}}"
LDAP_BIND_DN = "{{ldap.dn.bind}}"
LDAP_BIND_DN = "{{ldap.dn.administrator}}"
LDAP_BIND_PASSWORD = "{{ldap.bind_credential}}"
LDAP_SEARCH_FILTER = "(|(cn={0})(mail={0}))"
LDAP_START_TLS = False

View File

@ -1948,7 +1948,7 @@
"uid"
],
"bindDn": [
"{{ldap.dn.bind}}"
"{{ldap.dn.administrator}}"
],
"lastSync": [
"1737578007"

View File

@ -22,7 +22,7 @@
- name: "Import users, groups, etc. to LDAP"
shell: >
docker exec -i openldap ldapadd -x -D "{{ldap.dn.bind}}" -w "{{ldap.bind_credential}}" -c -f "{{ldif_docker_path}}import/{{ item | basename | regex_replace(r'\.j2$', '') }}"
docker exec -i openldap ldapadd -x -D "{{ldap.dn.administrator}}" -w "{{ldap.bind_credential}}" -c -f "{{ldif_docker_path}}import/{{ item | basename | regex_replace(r'\.j2$', '') }}"
register: ldapadd_result
changed_when: "'adding new entry' in ldapadd_result.stdout"
# Allow return code 0 (all entries added) or 68 (entry already exists)

View File

@ -34,7 +34,7 @@ services:
- '{{ldif_host_path}}:{{ldif_docker_path}}:ro' # Mounting all ldif files for import
healthcheck:
test: >
ldapsearch -x -H ldap://localhost:{{ldap_docker_port}} -b "{{ldap.dn.root}}" -D "{{ldap.dn.bind}}" -w "{{ldap.bind_credential}}"
ldapsearch -x -H ldap://localhost:{{ldap_docker_port}} -b "{{ldap.dn.root}}" -D "{{ldap.dn.administrator}}" -w "{{ldap.bind_credential}}"
interval: 30s
timeout: 10s
retries: 3

View File

@ -12,7 +12,7 @@ LDAP_PASSWORDS= ' ' # Comma separated li
LDAP_ROOT= {{ldap.dn.root}} # LDAP baseDN (or suffix) of the LDAP tree. Default: dc=example,dc=org
## Admin
LDAP_ADMIN_DN= {{ldap.dn.bind}}
LDAP_ADMIN_DN= {{ldap.dn.administrator}}
LDAP_CONFIG_ADMIN_ENABLED= yes
LDAP_CONFIG_ADMIN_USERNAME= {{applications.ldap.administrator_username}}
LDAP_CONFIG_ADMIN_PASSWORD= {{applications.ldap.administrator_password}}

View File

@ -9,5 +9,5 @@ LAM_CONFIGURATION_DATABASE= files
# LDAP Configuration
LDAP_SERVER= {{ldap.server.domain}} # domain of LDAP database root entry
LDAP_BASE_DN= {{ldap.dn.root}} # LDAP base DN to overwrite value generated by LDAP_DOMAIN
LDAP_USER= {{ldap.dn.bind}} # LDAP admin user (set as login user for LAM)
LDAP_USER= {{ldap.dn.administrator}} # LDAP admin user (set as login user for LAM)
LDAP_ADMIN_PASSWORD= {{ldap.bind_credential}} # LDAP admin password

View File

@ -1,6 +1,16 @@
# @See https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/user_auth_ldap.html
# @See https://chatgpt.com/c/67aa2d21-cb4c-800f-b1be-8629b6bd3f55
# @todo implement
#docker compose exec -u www-data application php occ app:enable user_ldap
occ config:app:set user_ldap installed_version --value "1.21.0"
- name: Activate Nextcloud LDAP App
command: "docker exec -u www-data {{ nextcloud_application_container_name }} php occ app:enable user_ldap"
- name: Load LDAP Nextcloud configuration variables
include_vars:
file: ldap.yml
- name: Set Nextcloud LDAP config
loop: "{{ nextcloud_ldap_configuration }}"
command: >
docker exec -u www-data {{ nextcloud_application_container_name }}
php occ config:app:set {{ item.appid }} {{ item.configkey }} --value "{{ item.configvalue }}"

View File

@ -0,0 +1,183 @@
nextcloud_ldap_configuration:
-
appid: "user_ldap"
configkey: "background_sync_interval"
configvalue: 43200
-
appid: "user_ldap"
configkey: "background_sync_offset"
configvalue: 0
-
appid: "user_ldap"
configkey: "background_sync_prefix"
configvalue: "s01"
-
appid: "user_ldap"
configkey: "enabled"
configvalue: "yes"
-
appid: "user_ldap"
configkey: "s01last_jpegPhoto_lookup"
configvalue: 0
-
appid: "user_ldap"
configkey: "s01ldap_agent_password"
configvalue: "{{ldap.bind_credential}}"
-
appid: "user_ldap"
configkey: "s01ldap_backup_port"
configvalue: "{{ ports.localhost.ldap.openldap }}" # This is just optimized for local port @todo implement for external ports as well
-
appid: "user_ldap"
configkey: "s01ldap_base"
configvalue: "{{ldap.dn.root}}"
-
appid: "user_ldap"
configkey: "s01ldap_base_groups"
configvalue: "{{ldap.dn.groups}}"
-
appid: "user_ldap"
configkey: "s01ldap_base_users"
configvalue: "{{ldap.dn.users}}"
-
appid: "user_ldap"
configkey: "s01ldap_cache_ttl"
configvalue: 600
-
appid: "user_ldap"
configkey: "s01ldap_configuration_active"
configvalue: 1
-
appid: "user_ldap"
configkey: "s01ldap_connection_timeout"
configvalue: 15
-
appid: "user_ldap"
configkey: "s01ldap_display_name"
configvalue: "cn"
-
appid: "user_ldap"
configkey: "s01ldap_dn"
configvalue: "{{ldap.dn.administrator}}"
-
appid: "user_ldap"
configkey: "s01ldap_email_attr"
configvalue: "mail"
-
appid: "user_ldap"
configkey: "s01ldap_experienced_admin"
configvalue: 0
-
appid: "user_ldap"
configkey: "s01ldap_gid_number"
configvalue: "gidNumber"
-
appid: "user_ldap"
configkey: "s01ldap_group_display_name"
configvalue: "cn"
-
appid: "user_ldap"
configkey: "s01ldap_group_filter"
configvalue: "(&(|(objectclass=groupOfUniqueNames)(objectclass=posixGroup)))"
-
appid: "user_ldap"
configkey: "s01ldap_group_filter_mode"
configvalue: 0
-
appid: "user_ldap"
configkey: "s01ldap_group_member_assoc_attribute"
configvalue: "uniqueMember"
-
appid: "user_ldap"
configkey: "s01ldap_groupfilter_objectclass"
configvalue: "groupOfUniqueNames\nposixGroup"
-
appid: "user_ldap"
configkey: "s01ldap_host"
configvalue: "openldap"
-
appid: "user_ldap"
configkey: "s01ldap_login_filter"
configvalue: "(&(|(objectclass=inetOrgPerson))(uid=%uid))"
-
appid: "user_ldap"
configkey: "s01ldap_login_filter_mode"
configvalue: 0
-
appid: "user_ldap"
configkey: "s01ldap_loginfilter_email"
configvalue: 0
-
appid: "user_ldap"
configkey: "s01ldap_loginfilter_username"
configvalue: 1
-
appid: "user_ldap"
configkey: "s01ldap_mark_remnants_as_disabled"
configvalue: 0
-
appid: "user_ldap"
configkey: "s01ldap_matching_rule_in_chain_state"
configvalue: "unknown"
-
appid: "user_ldap"
configkey: "s01ldap_nested_groups"
configvalue: 0
-
appid: "user_ldap"
configkey: "s01ldap_paging_size"
configvalue: 500
-
appid: "user_ldap"
configkey: "s01ldap_port"
configvalue: 389
-
appid: "user_ldap"
configkey: "s01ldap_turn_off_cert_check"
configvalue: 0
-
appid: "user_ldap"
configkey: "s01ldap_turn_on_pwd_change"
configvalue: 0
-
appid: "user_ldap"
configkey: "s01ldap_user_avatar_rule"
configvalue: "default"
-
appid: "user_ldap"
configkey: "s01ldap_user_filter_mode"
configvalue: 0
-
appid: "user_ldap"
configkey: "s01ldap_userfilter_objectclass"
configvalue: "inetOrgPerson"
-
appid: "user_ldap"
configkey: "s01ldap_userlist_filter"
configvalue: "(|(objectclass=inetOrgPerson))"
-
appid: "user_ldap"
configkey: "s01use_memberof_to_detect_membership"
configvalue: 1
-
appid: "user_ldap"
configkey: "types"
configvalue: "authentication"
-
appid: "user_ldap"
configkey: "s01ldap_expert_username_attr"
configvalue: "uid"

View File

@ -54,15 +54,12 @@ HINT:
--bs-white: var(--color-99); /* Original tone: White (#fff) */
--bs-gray: var(--color-50); /* Original tone: Gray (#6c757d) */
--bs-gray-dark: var(--color-20); /* Original tone: Dark Gray (#343a40) */
--bs-gray-100: var(--color-95); /* Original tone: Very Light Gray (#f8f9fa) */
--bs-gray-200: var(--color-90); /* Original tone: Lighter Gray (#e9ecef) */
--bs-gray-300: var(--color-85); /* Original tone: Light Gray (#dee2e6) */
--bs-gray-400: var(--color-80); /* Original tone: Gray (#ced4da) */
--bs-gray-500: var(--color-70); /* Original tone: Medium Gray (#adb5bd) */
--bs-gray-600: var(--color-50); /* Original tone: Gray (#6c757d) */
--bs-gray-700: var(--color-40); /* Original tone: Darker Gray (#495057) */
--bs-gray-800: var(--color-20); /* Original tone: Dark Gray (#343a40) */
--bs-gray-900: var(--color-10); /* Original tone: Very Dark Gray (#212529) */
{% for i in range(1, 10) %}
{# @see https://chatgpt.com/share/67bcd94e-bb44-800f-bf63-06d1ae0f5096 #}
{% set gray = i * 100 %}
{% set color = 100 - i * 10 %}
--bs-gray-{{ gray }}: var(--color-{{ "%02d" % color }});
{% endfor %}
--bs-primary: var(--color-65); /* Original tone: Blue (#0d6efd) */
--bs-light: var(--color-95); /* Original tone: Light (#f8f9fa) */
--bs-dark: var(--color-10); /* Original tone: Dark (#212529) */
@ -147,15 +144,12 @@ HINT:
--primary-high: var(--color-40); /* originally #487096 */
--primary-very-high: var(--color-20); /* originally #34516d */
--primary-50: var(--color-99); /* originally #f7f9fb */
--primary-100: var(--color-95); /* originally #eef3f7 */
--primary-200: var(--color-90); /* originally #e3ebf2 */
--primary-300: var(--color-80); /* originally #c7d6e4 */
--primary-400: var(--color-75); /* originally #acc2d7 */
--primary-500: var(--color-70); /* originally #90aeca */
--primary-600: var(--color-60); /* originally #7499bd */
--primary-700: var(--color-50); /* originally #5381ad */
--primary-800: var(--color-40); /* originally #487096 */
--primary-900: var(--color-20); /* originally #34516d */
{% for i in range(1, 10) %}
{# @see https://chatgpt.com/share/67bcd94e-bb44-800f-bf63-06d1ae0f5096 #}
{% set primary = i * 100 %}
{% set color = 100 - i * 8 %}
--primary-{{ primary }}: var(--color-{{ "%02d" % color }});
{% endfor %}
/* Header Primary Scale */
--header_primary-low: rgb(var(--color-rgb-75)); /* rgb(128, 180, 209) */
@ -177,15 +171,12 @@ HINT:
--tertiary-high: var(--color-40); /* originally #5886a0 */
--tertiary-hover: var(--color-20); /* originally #314a59 */
--tertiary-50: var(--color-99); /* originally #eaf0f3 */
--tertiary-100: var(--color-95); /* originally #e6edf1 */
--tertiary-200: var(--color-90); /* originally #e4ebf0 */
--tertiary-300: var(--color-85); /* originally #dfe8ee */
--tertiary-400: var(--color-75); /* originally #c8d8e1 */
--tertiary-500: var(--color-65); /* originally #b1c7d4 */
--tertiary-600: var(--color-60); /* originally #96b4c5 */
--tertiary-700: var(--color-55); /* originally #80a5b9 */
--tertiary-800: var(--color-50); /* originally #6b96ae */
--tertiary-900: var(--color-40); /* originally #5886a0 */
{% for i in range(1, 10) %}
{# @see https://chatgpt.com/share/67bcd94e-bb44-800f-bf63-06d1ae0f5096 #}
{% set tertiary = i * 100 %}
{% set color = 100 - i * 5 %}
--tertiary-{{ tertiary }}: var(--color-{{ "%02d" % color }});
{% endfor %}
/* Quaternary */
--quaternary-low: var(--color-80); /* originally #cfe0ea */
@ -237,15 +228,11 @@ HINT:
--color-primary-light-7: var(--color-61);
/* Alpha variants reference the base RGB variable */
--color-primary-alpha-10: rgba(var(--color-rgb-50), 0.10);
--color-primary-alpha-20: rgba(var(--color-rgb-50), 0.20);
--color-primary-alpha-30: rgba(var(--color-rgb-50), 0.30);
--color-primary-alpha-40: rgba(var(--color-rgb-50), 0.40);
--color-primary-alpha-50: rgba(var(--color-rgb-50), 0.50);
--color-primary-alpha-60: rgba(var(--color-rgb-50), 0.60);
--color-primary-alpha-70: rgba(var(--color-rgb-50), 0.70);
--color-primary-alpha-80: rgba(var(--color-rgb-50), 0.80);
--color-primary-alpha-90: rgba(var(--color-rgb-50), 0.90);
{% for i in range(1, 10) %}
{# @see https://chatgpt.com/share/67bcd94e-bb44-800f-bf63-06d1ae0f5096 #}
{% set alpha = i * 10 %}
--color-primary-alpha-{{ alpha }}: rgba(var(--color-rgb-50), 0.{{ alpha }});
{% endfor %}
--color-primary-hover: var(--color-primary-dark-1);
--color-primary-active: var(--color-primary-dark-2);
@ -270,15 +257,11 @@ HINT:
--color-secondary-light-3: var(--color-94);
--color-secondary-light-4: var(--color-95);
--color-secondary-alpha-10: rgba(var(--color-rgb-80), 0.10);
--color-secondary-alpha-20: rgba(var(--color-rgb-80), 0.20);
--color-secondary-alpha-30: rgba(var(--color-rgb-80), 0.30);
--color-secondary-alpha-40: rgba(var(--color-rgb-80), 0.40);
--color-secondary-alpha-50: rgba(var(--color-rgb-80), 0.50);
--color-secondary-alpha-60: rgba(var(--color-rgb-80), 0.60);
--color-secondary-alpha-70: rgba(var(--color-rgb-80), 0.70);
--color-secondary-alpha-80: rgba(var(--color-rgb-80), 0.80);
--color-secondary-alpha-90: rgba(var(--color-rgb-80), 0.90);
{% for i in range(1, 10) %}
{# @see https://chatgpt.com/share/67bcd94e-bb44-800f-bf63-06d1ae0f5096 #}
{% set alpha = i * 10 %}
--color-secondary-alpha-{{ alpha }}: rgba(var(--color-rgb-80), 0.{{ alpha }});
{% endfor %}
--color-secondary-button: var(--color-secondary-dark-4);
--color-secondary-hover: var(--color-secondary-dark-5);
@ -370,18 +353,12 @@ HINT:
/* Keycloak */
:root{
/* --- Palette Black (Graustufen) --- */
--pf-v5-global--palette--black-100: var(--color-95); /* #fafafa */
--pf-v5-global--palette--black-150: var(--color-90); /* #f5f5f5 */
--pf-v5-global--palette--black-200: var(--color-85); /* #f0f0f0 */
--pf-v5-global--palette--black-300: var(--color-75); /* #d2d2d2 */
--pf-v5-global--palette--black-400: var(--color-65); /* #b8bbbe */
--pf-v5-global--palette--black-500: var(--color-50); /* #8a8d90 */
--pf-v5-global--palette--black-600: var(--color-40); /* #6a6e73 */
--pf-v5-global--palette--black-700: var(--color-30); /* #4f5255 */
--pf-v5-global--palette--black-800: var(--color-25); /* #3c3f42 */
--pf-v5-global--palette--black-850: var(--color-20); /* #212427 */
--pf-v5-global--palette--black-900: var(--color-10); /* #151515 */
--pf-v5-global--palette--black-1000: var(--color-05); /* #030303 */
{% for i in range(1, 21) %}
{# @see https://chatgpt.com/share/67bcd94e-bb44-800f-bf63-06d1ae0f5096 #}
{% set black = i * 50 %}
{% set color = 100 - i * 5 %}
--pf-v5-global--palette--black-{{ black }}: var(--color-{{ "%02d" % color }});
{% endfor %}
/* --- White --- */
--pf-v5-global--palette--white: var(--color-99);
@ -463,9 +440,12 @@ HINT:
--pf-v5-global--icon--Color--light--dark: var(--color-40);
--pf-v5-global--icon--Color--dark--dark: var(--color-10);
{# Additional Configuration #}
--pf-v5-c-button--m-tertiary--BackgroundColor: var(--color-62);
}
.pf-v5-c-button.pf-m-tertiary {
--pf-v5-c-button--m-tertiary--BackgroundColor: var(--color-70);
{# Assume that the following line is necessary due to load order #}
background-color: var(--pf-v5-c-button--m-tertiary--BackgroundColor);
}
/* Additional Keykloak Configuration */
@ -863,6 +843,10 @@ html[native-dark-active] .btn, .btn {
color: var(--color-40);
}
.navbar-nav {
--bs-nav-link-hover-color: var(--color-17);
}
.dropdown-item {
color: var(--color-40);
background-color: var(--color-80);
@ -960,7 +944,7 @@ html.ng-csp header#header{
background-color: var(--color-80);
/* New Gradient based on original background (80 -5, 80, 80 +1, 80 +5) */
background: linear-gradient({{ range(0, 361) | random }}deg, var(--color-75), var(--color-80), var(--color-81), var(--color-85));
color: var(--color-90);
color: var(--color-17);
}
.files-list__row-name button, button.button-vue{
@ -1038,6 +1022,10 @@ div.page-wrapper{
background-color: none;
}
.card-header-title {
color: var(--color-37);
}
/* PHP MyAdmin */
#pma_navigation {
background: linear-gradient(to right, var(--color-95), var(--color-85));