diff --git a/group_vars/all/13_ldap.yml b/group_vars/all/13_ldap.yml index 466edcfb..3d8afa4d 100644 --- a/group_vars/all/13_ldap.yml +++ b/group_vars/all/13_ldap.yml @@ -14,22 +14,22 @@ _ldap_domain: "{{ PRIMARY_DOMAIN }}" # LDAP is jsut listening to _ldap_user_id: "uid" _ldap_filters_users_all: "(|(objectclass=inetOrgPerson))" -ldap: +LDAP: # Distinguished Names (DN) - dn: + DN: # ------------------------------------------------------------------------- # Base DN / Suffix # This is the top-level naming context for your directory, used as the # default search base for most operations (e.g. adding users, groups). # Example: “dc=example,dc=com” - root: "{{ LDAP_DN_BASE }}" - administrator: + ROOT: "{{ LDAP_DN_BASE }}" + ADMINISTRATOR: # ------------------------------------------------------------------------- # Data-Tree Administrator Bind DN # The DN used to authenticate for regular directory operations under # the data tree (adding users, modifying attributes, creating OUs, etc.). # Typically: “cn=admin,dc=example,dc=com” - data: "cn={{ applications['svc-db-openldap'].users.administrator.username }},{{ LDAP_DN_BASE }}" + DATA: "cn={{ applications['svc-db-openldap'].users.administrator.username }},{{ LDAP_DN_BASE }}" # ------------------------------------------------------------------------- # Config-Tree Administrator Bind DN @@ -37,9 +37,9 @@ ldap: # need to load or modify schema, overlays, modules, or other server- # level settings. # Typically: “cn=admin,cn=config” - configuration: "cn={{ applications['svc-db-openldap'].users.administrator.username }},cn=config" + CONFIGURATION: "cn={{ applications['svc-db-openldap'].users.administrator.username }},cn=config" - ou: + OU: # ------------------------------------------------------------------------- # Organizational Units (OUs) # Pre-created containers in the directory tree to logically separate entries: @@ -47,9 +47,9 @@ ldap: # – groups: Contains organizational or business groups (e.g., departments, teams). # – roles: Contains application-specific RBAC roles # (e.g., "cn=app1-user", "cn=yourls-admin"). - users: "ou=users,{{ LDAP_DN_BASE }}" - groups: "ou=groups,{{ LDAP_DN_BASE }}" - roles: "ou=roles,{{ LDAP_DN_BASE }}" + USERS: "ou=users,{{ LDAP_DN_BASE }}" + GROUPS: "ou=groups,{{ LDAP_DN_BASE }}" + ROLES: "ou=roles,{{ LDAP_DN_BASE }}" # ------------------------------------------------------------------------- # Additional Notes @@ -59,17 +59,17 @@ ldap: # for ordinary user/group operations, and vice versa. # Password to access dn.bind - bind_credential: "{{ applications | get_app_conf('svc-db-openldap', 'credentials.administrator_database_password') }}" - server: - domain: "{{ _ldap_name if _ldap_docker_network_enabled else _ldap_domain }}" # Mapping for public or locale access - port: "{{ _ldap_server_port }}" - uri: "{{ _ldap_protocol }}://{{ _ldap_name if _ldap_docker_network_enabled else _ldap_domain }}:{{ _ldap_server_port }}" - security: "" #TLS, SSL - Leave empty for none - network: - local: "{{ _ldap_docker_network_enabled }}" # Uses the application configuration to define if local network should be available or not - user: - objects: - structural: + BIND_CREDENTIAL: "{{ applications | get_app_conf('svc-db-openldap', 'credentials.administrator_database_password') }}" + SERVER: + DOMAIN: "{{ _ldap_name if _ldap_docker_network_enabled else _ldap_domain }}" # Mapping for public or locale access + PORT: "{{ _ldap_server_port }}" + URI: "{{ _ldap_protocol }}://{{ _ldap_name if _ldap_docker_network_enabled else _ldap_domain }}:{{ _ldap_server_port }}" + SECURITY: "" #TLS, SSL - Leave empty for none + NETWORK: + LOCAL: "{{ _ldap_docker_network_enabled }}" # Uses the application configuration to define if local network should be available or not + USER: + OBJECTS: + STRUCTURAL: - person # Structural Classes define the core identity of an entry: # • Specify mandatory attributes (e.g. sn, cn) # • Each entry must have exactly one structural class @@ -77,26 +77,26 @@ ldap: # (e.g. mail, employeeNumber) - posixAccount # Provides UNIX account attributes (uidNumber, gidNumber, # homeDirectory) - auxiliary: - nextloud_user: "nextcloudUser" # Auxiliary Classes attach optional attributes without + AUXILIARY: + NEXTCLOUD_USER: "nextcloudUser" # Auxiliary Classes attach optional attributes without # changing the entry’s structural role. Here they add # nextcloudQuota and nextcloudEnabled for Nextcloud. - ssh_public_key: "ldapPublicKey" # Allows storing SSH public keys for services like Gitea. - attributes: + 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: - users: - login: "(&{{ _ldap_filters_users_all }}({{_ldap_user_id}}=%{{_ldap_user_id}}))" - all: "{{ _ldap_filters_users_all }}" - rbac: - flavors: + ID: "{{ _ldap_user_id }}" + MAIL: "mail" + FULLNAME: "cn" + FIRSTNAME: "givenname" + SURNAME: "sn" + SSH_PUBLIC_KEY: "sshPublicKey" + NEXTCLOUD_QUOTA: "nextcloudQuota" + FILTERS: + USERS: + LOGIN: "(&{{ _ldap_filters_users_all }}({{_ldap_user_id}}=%{{_ldap_user_id}}))" + ALL: "{{ _ldap_filters_users_all }}" + RBAC: + FLAVORS: # Valid values posixGroup, groupOfNames - groupOfNames # - posixGroup diff --git a/roles/svc-db-openldap/filter_plugins/build_ldap_nested_group_entries.py b/roles/svc-db-openldap/filter_plugins/build_ldap_nested_group_entries.py index 406c65c7..0aa172a0 100644 --- a/roles/svc-db-openldap/filter_plugins/build_ldap_nested_group_entries.py +++ b/roles/svc-db-openldap/filter_plugins/build_ldap_nested_group_entries.py @@ -8,12 +8,12 @@ def build_ldap_nested_group_entries(applications, users, ldap): 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"] + 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", []) + flavors = ldap.get("RBAC").get("FLAVORS") for application_id, app_config in applications.items(): # Compute the DN for the application-level OU diff --git a/roles/svc-db-openldap/filter_plugins/build_ldap_role_entries.py b/roles/svc-db-openldap/filter_plugins/build_ldap_role_entries.py index 3319eef3..0aa6b97a 100644 --- a/roles/svc-db-openldap/filter_plugins/build_ldap_role_entries.py +++ b/roles/svc-db-openldap/filter_plugins/build_ldap_role_entries.py @@ -16,10 +16,10 @@ def build_ldap_role_entries(applications, users, ldap): } group_id = application_config.get("group_id") - user_dn_base = ldap["dn"]["ou"]["users"] - ldap_user_attr = ldap["user"]["attributes"]["id"] - role_dn_base = ldap["dn"]["ou"]["roles"] - flavors = ldap.get("rbac", {}).get("flavors", []) + user_dn_base = ldap["DN"]["OU"]["USERS"] + ldap_user_attr = ldap["USER"]["ATTRIBUTES"]["ID"] + role_dn_base = ldap["DN"]["OU"]["ROLES"] + flavors = ldap.get("RBAC").get("FLAVORS") for role_name, role_conf in roles.items(): group_cn = f"{application_id}-{role_name}" diff --git a/roles/svc-db-openldap/handlers/main.yml b/roles/svc-db-openldap/handlers/main.yml index 0b582caa..b5394736 100644 --- a/roles/svc-db-openldap/handlers/main.yml +++ b/roles/svc-db-openldap/handlers/main.yml @@ -1,6 +1,6 @@ - name: Load memberof module from file in OpenLDAP container shell: > - docker exec -i {{ openldap_name }} ldapmodify -Y EXTERNAL -H ldapi:/// -f {{openldap_ldif_docker_path}}configuration/01_member_of_configuration.ldif + docker exec -i {{ openldap_name }} ldapmodify -Y EXTERNAL -H ldapi:/// -f {{ openldap_ldif_docker_path }}configuration/01_member_of_configuration.ldif listen: - "Import configuration LDIF files" - "Import all LDIF files" @@ -10,7 +10,7 @@ - name: Refint Module Activation for OpenLDAP shell: > - docker exec -i {{ openldap_name }} ldapadd -Y EXTERNAL -H ldapi:/// -f {{openldap_ldif_docker_path}}configuration/02_member_of_configuration.ldif + docker exec -i {{ openldap_name }} ldapadd -Y EXTERNAL -H ldapi:/// -f {{ openldap_ldif_docker_path }}configuration/02_member_of_configuration.ldif listen: - "Import configuration LDIF files" - "Import all LDIF files" @@ -22,7 +22,7 @@ - name: "Import schemas" shell: > - docker exec -i {{ openldap_name }} ldapadd -Y EXTERNAL -H ldapi:/// -f "{{openldap_ldif_docker_path}}schema/{{ item | basename | regex_replace('\.j2$', '') }}" + docker exec -i {{ openldap_name }} ldapadd -Y EXTERNAL -H ldapi:/// -f "{{ openldap_ldif_docker_path }}schema/{{ item | basename | regex_replace('\.j2$', '') }}" register: ldapadd_result changed_when: "'adding new entry' in ldapadd_result.stdout" failed_when: ldapadd_result.rc not in [0, 80] @@ -33,7 +33,7 @@ - name: Refint Overlay Configuration for OpenLDAP shell: > - docker exec -i {{ openldap_name }} ldapmodify -Y EXTERNAL -H ldapi:/// -f {{openldap_ldif_docker_path}}configuration/03_member_of_configuration.ldif + docker exec -i {{ openldap_name }} ldapmodify -Y EXTERNAL -H ldapi:/// -f {{ openldap_ldif_docker_path }}configuration/03_member_of_configuration.ldif listen: - "Import configuration LDIF files" - "Import all LDIF files" @@ -45,7 +45,7 @@ - name: "Import users, groups, etc. to LDAP" shell: > - docker exec -i {{ openldap_name }} ldapadd -x -D "{{ldap.dn.administrator.data}}" -w "{{ldap.bind_credential}}" -c -f "{{openldap_ldif_docker_path}}groups/{{ item | basename | regex_replace('\.j2$', '') }}" + docker exec -i {{ openldap_name }} ldapadd -x -D "{{LDAP.DN.ADMINISTRATOR.DATA}}" -w "{{ LDAP.BIND_CREDENTIAL }}" -c -f "{{ openldap_ldif_docker_path }}groups/{{ item | basename | regex_replace('\.j2$', '') }}" register: ldapadd_result changed_when: "'adding new entry' in ldapadd_result.stdout" failed_when: ldapadd_result.rc not in [0, 20, 68, 65] diff --git a/roles/svc-db-openldap/tasks/01_credentials.yml b/roles/svc-db-openldap/tasks/01_credentials.yml index 75b88b91..7bb36463 100644 --- a/roles/svc-db-openldap/tasks/01_credentials.yml +++ b/roles/svc-db-openldap/tasks/01_credentials.yml @@ -28,7 +28,7 @@ - name: "Generate hash for Database Admin password" shell: | docker exec {{ openldap_name }} \ - slappasswd -s "{{ ldap.bind_credential }}" + slappasswd -s "{{ LDAP.BIND_CREDENTIAL }}" register: database_admin_pw_hash - name: "Reset Database Admin password in LDAP (olcRootPW)" diff --git a/roles/svc-db-openldap/tasks/03_users.yml b/roles/svc-db-openldap/tasks/03_users.yml index bde2dd79..23d824f9 100644 --- a/roles/svc-db-openldap/tasks/03_users.yml +++ b/roles/svc-db-openldap/tasks/03_users.yml @@ -3,11 +3,11 @@ ############################################################################### - name: Ensure LDAP users exist community.general.ldap_entry: - dn: "{{ ldap.user.attributes.id }}={{ item.key }},{{ ldap.dn.ou.users }}" + dn: "{{ LDAP.USER.ATTRIBUTES.ID }}={{ item.key }},{{ LDAP.DN.OU.USERS }}" server_uri: "{{ openldap_server_uri }}" - bind_dn: "{{ ldap.dn.administrator.data }}" - bind_pw: "{{ ldap.bind_credential }}" - objectClass: "{{ ldap.user.objects.structural }}" + bind_dn: "{{ LDAP.DN.ADMINISTRATOR.DATA }}" + bind_pw: "{{ LDAP.BIND_CREDENTIAL }}" + objectClass: "{{ LDAP.USER.OBJECTS.STRUCTURAL }}" attributes: uid: "{{ item.value.username }}" sn: "{{ item.value.sn | default(item.key) }}" @@ -29,12 +29,12 @@ ############################################################################### - name: Ensure required objectClass values and mail address are present community.general.ldap_attrs: - dn: "{{ ldap.user.attributes.id }}={{ item.key }},{{ ldap.dn.ou.users }}" + dn: "{{ LDAP.USER.ATTRIBUTES.ID }}={{ item.key }},{{ LDAP.DN.OU.USERS }}" server_uri: "{{ openldap_server_uri }}" - bind_dn: "{{ ldap.dn.administrator.data }}" - bind_pw: "{{ ldap.bind_credential }}" + bind_dn: "{{ LDAP.DN.ADMINISTRATOR.DATA }}" + bind_pw: "{{ LDAP.BIND_CREDENTIAL }}" attributes: - objectClass: "{{ ldap.user.objects.structural }}" + objectClass: "{{ LDAP.USER.OBJECTS.STRUCTURAL }}" mail: "{{ item.value.email }}" state: exact async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}" @@ -45,10 +45,10 @@ - name: "Ensure container for application roles exists" community.general.ldap_entry: - dn: "{{ ldap.dn.ou.roles }}" + dn: "{{ LDAP.DN.OU.ROLES }}" server_uri: "{{ openldap_server_uri }}" - bind_dn: "{{ ldap.dn.administrator.data }}" - bind_pw: "{{ ldap.bind_credential }}" + bind_dn: "{{ LDAP.DN.ADMINISTRATOR.DATA }}" + bind_pw: "{{ LDAP.BIND_CREDENTIAL }}" objectClass: organizationalUnit attributes: ou: roles diff --git a/roles/svc-db-openldap/tasks/04_update.yml b/roles/svc-db-openldap/tasks/04_update.yml index ccfba116..47b1f847 100644 --- a/roles/svc-db-openldap/tasks/04_update.yml +++ b/roles/svc-db-openldap/tasks/04_update.yml @@ -1,22 +1,22 @@ - name: Gather all users with their current objectClass list community.general.ldap_search: server_uri: "{{ openldap_server_uri }}" - bind_dn: "{{ ldap.dn.administrator.data }}" - bind_pw: "{{ ldap.bind_credential }}" - dn: "{{ ldap.dn.ou.users }}" + bind_dn: "{{ LDAP.DN.ADMINISTRATOR.DATA }}" + bind_pw: "{{ LDAP.BIND_CREDENTIAL }}" + dn: "{{ LDAP.DN.OU.USERS }}" scope: subordinate - filter: "{{ ldap.filters.users.all }}" + filter: "{{ LDAP.FILTERS.USERS.ALL }}" attrs: - dn - objectClass - - "{{ ldap.user.attributes.id }}" + - "{{ LDAP.USER.ATTRIBUTES.ID }}" register: ldap_users_with_classes - name: Add only missing auxiliary classes community.general.ldap_attrs: server_uri: "{{ openldap_server_uri }}" - bind_dn: "{{ ldap.dn.administrator.data }}" - bind_pw: "{{ ldap.bind_credential }}" + bind_dn: "{{ LDAP.DN.ADMINISTRATOR.DATA }}" + bind_pw: "{{ LDAP.BIND_CREDENTIAL }}" dn: "{{ item.dn }}" attributes: objectClass: "{{ missing_auxiliary }}" @@ -28,7 +28,7 @@ label: "{{ item.dn }}" vars: missing_auxiliary: >- - {{ (ldap.user.objects.auxiliary.values() | list) + {{ (LDAP.USER.OBJECTS.AUXILIARY.values() | list) | difference(item.objectClass | default([])) }} when: missing_auxiliary | length > 0 diff --git a/roles/svc-db-openldap/tasks/schemas/nextcloud.yml b/roles/svc-db-openldap/tasks/schemas/nextcloud.yml index 58776bc7..2abcc90c 100644 --- a/roles/svc-db-openldap/tasks/schemas/nextcloud.yml +++ b/roles/svc-db-openldap/tasks/schemas/nextcloud.yml @@ -8,9 +8,9 @@ vars: schema_name: "nextcloud" attribute_defs: - - "( 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 )" + - "( 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: - - "( 1.3.6.1.4.1.99999.2 NAME 'nextcloudUser' DESC 'Auxiliary class for Nextcloud attributes' AUXILIARY MAY ( {{ ldap.user.attributes.nextcloud_quota }} ) )" + - "( 1.3.6.1.4.1.99999.2 NAME '{{ LDAP.USER.OBJECTS.AUXILIARY.NEXTCLOUD_USER }}' DESC 'Auxiliary class for Nextcloud attributes' AUXILIARY MAY ( {{ LDAP.USER.ATTRIBUTES.NEXTCLOUD_QUOTA }} ) )" command: > ldapsm -s {{ openldap_server_uri }} diff --git a/roles/svc-db-openldap/tasks/schemas/openssh_lpk.yml b/roles/svc-db-openldap/tasks/schemas/openssh_lpk.yml index 51b6c613..a9ed9b14 100644 --- a/roles/svc-db-openldap/tasks/schemas/openssh_lpk.yml +++ b/roles/svc-db-openldap/tasks/schemas/openssh_lpk.yml @@ -8,16 +8,16 @@ vars: schema_name: "openssh-lpk" attribute_defs: - - "( 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.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 )" objectclass_defs: - >- ( 1.3.6.1.4.1.24552.2.1 - NAME '{{ ldap.user.objects.auxiliary.ssh_public_key }}' + NAME '{{ LDAP.USER.OBJECTS.AUXILIARY.SSH_PUBLIC_KEY }}' DESC 'Auxiliary class for OpenSSH public keys' SUP top AUXILIARY - MAY ( {{ ldap.user.attributes.ssh_public_key }} $ sshFingerprint ) ) + MAY ( {{ LDAP.USER.ATTRIBUTES.SSH_PUBLIC_KEY }} $ sshFingerprint ) ) command: > ldapsm diff --git a/roles/svc-db-openldap/templates/docker-compose.yml.j2 b/roles/svc-db-openldap/templates/docker-compose.yml.j2 index 9ee4c454..0781c087 100644 --- a/roles/svc-db-openldap/templates/docker-compose.yml.j2 +++ b/roles/svc-db-openldap/templates/docker-compose.yml.j2 @@ -10,12 +10,12 @@ {% endif %} volumes: - 'data:/bitnami/openldap' - - '{{openldap_ldif_host_path}}:{{openldap_ldif_docker_path}}:ro' + - '{{openldap_ldif_host_path}}:{{ openldap_ldif_docker_path }}:ro' healthcheck: test: > bash -c ' ldapsearch -x -H ldap://localhost:{{ openldap_docker_port_open }} \ - -D "{{ ldap.dn.administrator.data }}" -w "{{ ldap.bind_credential }}" -b "{{ ldap.dn.root }}" > /dev/null \ + -D "{{ LDAP.DN.ADMINISTRATOR.DATA }}" -w "{{ LDAP.BIND_CREDENTIAL }}" -b "{{ LDAP.DN.ROOT }}" > /dev/null \ && ldapsearch -Y EXTERNAL -H ldapi:/// \ -b cn=config "(&(objectClass=olcOverlayConfig)(olcOverlay=memberof))" \ | grep "olcOverlay:" | grep -q "memberof" diff --git a/roles/svc-db-openldap/templates/env.j2 b/roles/svc-db-openldap/templates/env.j2 index 28e0ada4..56f2b9e4 100644 --- a/roles/svc-db-openldap/templates/env.j2 +++ b/roles/svc-db-openldap/templates/env.j2 @@ -4,15 +4,15 @@ # GENERAL ## Admin (Data) LDAP_ADMIN_USERNAME= {{ applications | get_app_conf(application_id, 'users.administrator.username') }} # LDAP database admin user. -LDAP_ADMIN_PASSWORD= {{ldap.bind_credential}} # LDAP database admin password. +LDAP_ADMIN_PASSWORD= {{ LDAP.BIND_CREDENTIAL }} # LDAP database admin password. ## Users LDAP_USERS= ' ' # Comma separated list of LDAP users to create in the default LDAP tree. Default: user01,user02 LDAP_PASSWORDS= ' ' # Comma separated list of passwords to use for LDAP users. Default: bitnami1,bitnami2 -LDAP_ROOT= {{ldap.dn.root}} # LDAP baseDN (or suffix) of the LDAP tree. Default: dc=example,dc=org +LDAP_ROOT= {{ LDAP.DN.ROOT }} # LDAP baseDN (or suffix) of the LDAP tree. Default: dc=example,dc=org ## Admin (Config) -LDAP_ADMIN_DN= {{ldap.dn.administrator.data}} +LDAP_ADMIN_DN= {{LDAP.DN.ADMINISTRATOR.DATA}} LDAP_CONFIG_ADMIN_ENABLED= yes LDAP_CONFIG_ADMIN_USERNAME= {{ applications | get_app_conf(application_id, 'users.administrator.username') }} LDAP_CONFIG_ADMIN_PASSWORD= {{ applications | get_app_conf(application_id, 'credentials.administrator_password') }} diff --git a/roles/svc-db-openldap/vars/main.yml b/roles/svc-db-openldap/vars/main.yml index 7a97b77c..df7de847 100644 --- a/roles/svc-db-openldap/vars/main.yml +++ b/roles/svc-db-openldap/vars/main.yml @@ -4,7 +4,7 @@ application_id: "svc-db-openldap" openldap_docker_port_secure: 636 openldap_docker_port_open: 389 openldap_server_uri: "ldap://127.0.0.1:{{ ports.localhost.ldap[application_id] }}" -openldap_bind_dn: "{{ ldap.dn.administrator.configuration }}" +openldap_bind_dn: "{{ LDAP.DN.ADMINISTRATOR.CONFIGURATION }}" openldap_bind_pw: "{{ applications | get_app_conf(application_id, 'credentials.administrator_password', True) }}" # LDIF Variables diff --git a/roles/web-app-bigbluebutton/templates/env.j2 b/roles/web-app-bigbluebutton/templates/env.j2 index 6ca5cfa1..a0e79b59 100644 --- a/roles/web-app-bigbluebutton/templates/env.j2 +++ b/roles/web-app-bigbluebutton/templates/env.j2 @@ -170,21 +170,21 @@ OAUTH2_REDIRECT= # LDAP_SERVER=ldap.example.com # LDAP_PORT=389 # LDAP_METHOD=plain -# LDAP_UID={{ ldap.user.attributes.id }} +# LDAP_UID={{ LDAP.USER.ATTRIBUTES.ID }} # LDAP_BASE=dc=example,dc=com # LDAP_AUTH=simple # LDAP_BIND_DN=cn=admin,dc=example,dc=com # LDAP_PASSWORD=password # LDAP_ROLE_FIELD=ou # LDAP_FILTER=(&(attr1=value1)(attr2=value2)) -LDAP_SERVER="{{ ldap.server.domain }}" -LDAP_PORT="{{ ldap.server.port }}" +LDAP_SERVER="{{ LDAP.SERVER.DOMAIN }}" +LDAP_PORT="{{ LDAP.SERVER.PORT }}" LDAP_METHOD= -LDAP_UID={{ ldap.user.attributes.id }} -LDAP_BASE="{{ ldap.dn.root }}" -LDAP_BIND_DN="{{ ldap.dn.administrator.data }}" +LDAP_UID={{ LDAP.USER.ATTRIBUTES.ID }} +LDAP_BASE="{{ LDAP.DN.ROOT }}" +LDAP_BIND_DN="{{ LDAP.DN.ADMINISTRATOR.DATA }}" LDAP_AUTH=password -LDAP_PASSWORD="{{ ldap.bind_credential }}" +LDAP_PASSWORD="{{ LDAP.BIND_CREDENTIAL }}" LDAP_ROLE_FIELD= LDAP_FILTER= {% endif %} diff --git a/roles/web-app-discourse/templates/config.yml.j2 b/roles/web-app-discourse/templates/config.yml.j2 index cf47293e..a4594964 100644 --- a/roles/web-app-discourse/templates/config.yml.j2 +++ b/roles/web-app-discourse/templates/config.yml.j2 @@ -150,16 +150,16 @@ run: - exec: rails r "SiteSetting.ldap_sync_enabled = true" # LDAP connection settings - - exec: rails r "SiteSetting.ldap_sync_host = '{{ ldap.server.domain }}'" - - exec: rails r "SiteSetting.ldap_sync_port = {{ ldap.server.port }}" + - exec: rails r "SiteSetting.ldap_sync_host = '{{ LDAP.SERVER.DOMAIN }}'" + - exec: rails r "SiteSetting.ldap_sync_port = {{ LDAP.SERVER.PORT }}" - exec: rails r "SiteSetting.ldap_encryption = 'simple_tls'" - - exec: rails r "SiteSetting.ldap_base_dn = '{{ ldap.dn.root }}'" - - exec: rails r "SiteSetting.ldap_bind_dn = '{{ ldap.dn.administrator.data }}'" - - exec: rails r "SiteSetting.ldap_bind_password = '{{ ldap.bind_credential }}'" + - exec: rails r "SiteSetting.ldap_base_dn = '{{ LDAP.DN.ROOT }}'" + - exec: rails r "SiteSetting.ldap_bind_dn = '{{ LDAP.DN.ADMINISTRATOR.DATA }}'" + - exec: rails r "SiteSetting.ldap_bind_password = '{{ LDAP.BIND_CREDENTIAL }}'" # LDAP additional configuration - - exec: rails r "SiteSetting.ldap_user_filter = '{{ ldap.filters.users.login }}'" - - exec: rails r "SiteSetting.ldap_group_base_dn = '{{ ldap.dn.ou.groups }}'" + - exec: rails r "SiteSetting.ldap_user_filter = '{{ LDAP.FILTERS.USERS.LOGIN }}'" + - exec: rails r "SiteSetting.ldap_group_base_dn = '{{ LDAP.DN.OU.GROUPS }}'" - exec: rails r "SiteSetting.ldap_group_member_check = 'memberUid'" - exec: rails r "SiteSetting.ldap_sync_period = 1" diff --git a/roles/web-app-espocrm/templates/env.j2 b/roles/web-app-espocrm/templates/env.j2 index f08c38c4..1112d266 100644 --- a/roles/web-app-espocrm/templates/env.j2 +++ b/roles/web-app-espocrm/templates/env.j2 @@ -63,13 +63,13 @@ ESPOCRM_CONFIG_OUTBOUND_EMAIL_FROM_ADDRESS={{ users['contact'].email }} # ------------------------------------------------ {% if applications | get_app_conf(application_id, 'features.ldap', False) %} ESPOCRM_CONFIG_AUTHENTICATION_METHOD=Ldap -ESPOCRM_CONFIG_LDAP_HOST={{ ldap.server.domain }} -ESPOCRM_CONFIG_LDAP_PORT={{ ldap.server.port }} +ESPOCRM_CONFIG_LDAP_HOST={{ LDAP.SERVER.DOMAIN }} +ESPOCRM_CONFIG_LDAP_PORT={{ LDAP.SERVER.PORT }} # ESPOCRM_CONFIG_LDAP_SECURITY: "", SSL or TLS -ESPOCRM_CONFIG_LDAP_SECURITY={{ ldap.server.security }} -ESPOCRM_CONFIG_LDAP_USERNAME={{ ldap.dn.administrator.data }} -ESPOCRM_CONFIG_LDAP_PASSWORD={{ ldap.bind_credential }} -ESPOCRM_CONFIG_LDAP_BASE_DN={{ ldap.dn.ou.users }} +ESPOCRM_CONFIG_LDAP_SECURITY={{ LDAP.SERVER.SECURITY }} +ESPOCRM_CONFIG_LDAP_USERNAME={{ LDAP.DN.ADMINISTRATOR.DATA }} +ESPOCRM_CONFIG_LDAP_PASSWORD={{ LDAP.BIND_CREDENTIAL }} +ESPOCRM_CONFIG_LDAP_BASE_DN={{ LDAP.DN.OU.USERS }} ESPOCRM_CONFIG_LDAP_USER_LOGIN_FILTER=(sAMAccountName=%USERNAME%) {% endif %} diff --git a/roles/web-app-friendica/templates/ldapauth.config.php.j2 b/roles/web-app-friendica/templates/ldapauth.config.php.j2 index 5a5478d1..833c9d6a 100644 --- a/roles/web-app-friendica/templates/ldapauth.config.php.j2 +++ b/roles/web-app-friendica/templates/ldapauth.config.php.j2 @@ -9,26 +9,26 @@ return [ // ldap_server (String) // ldap hostname server - required // Example: ldap_server = host.example.com - 'ldap_server' => '{{ ldap.server.uri }}', + '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_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_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_searchdn' => '{{ LDAP.DN.OU.USERS }}', // ldap_userattr (String) // attribute to find username - required // Example: ldap_userattr = uid - 'ldap_userattr' => '{{ ldap.user.attributes.id }}', + 'ldap_userattr' => '{{ LDAP.USER.ATTRIBUTES.ID }}', // ldap_group (String) // DN of the group whose member can auth on Friendica - optional @@ -42,10 +42,10 @@ return [ // ldap_autocreateaccount_emailattribute (String) // attribute to get email - optional - default : 'mail' - 'ldap_autocreateaccount_emailattribute' => '{{ ldap.user.attributes.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 }}', + 'ldap_autocreateaccount_nameattribute' => '{{ LDAP.USER.ATTRIBUTES.FIRSTNAME }}', ], ]; \ No newline at end of file diff --git a/roles/web-app-funkwhale/templates/env.j2 b/roles/web-app-funkwhale/templates/env.j2 index 54daa882..f68e0606 100644 --- a/roles/web-app-funkwhale/templates/env.j2 +++ b/roles/web-app-funkwhale/templates/env.j2 @@ -108,12 +108,12 @@ DJANGO_SECRET_KEY={{applications | get_app_conf(application_id, 'credentials.dja # Commit: https://gitea.fudaoyuan.icu/Github/funkwhale/commit/4ce46ff2a000646a3dbab80f0ca9fd8d7f8ae24c LDAP_ENABLED = True -LDAP_SERVER_URI = "{{ ldap.server.uri }}" -LDAP_BIND_DN = "{{ ldap.dn.administrator.data }}" -LDAP_BIND_PASSWORD = "{{ ldap.bind_credential }}" -LDAP_SEARCH_FILTER = "{{ ldap.filters.users.login | replace('%' ~ ldap.user.attributes.id, '{0}') }}" +LDAP_SERVER_URI = "{{ LDAP.SERVER.URI }}" +LDAP_BIND_DN = "{{ LDAP.DN.ADMINISTRATOR.DATA }}" +LDAP_BIND_PASSWORD = "{{ LDAP.BIND_CREDENTIAL }}" +LDAP_SEARCH_FILTER = "{{ LDAP.FILTERS.USERS.LOGIN | replace('%' ~ LDAP.USER.ATTRIBUTES.ID, '{0}') }}" LDAP_START_TLS = False -LDAP_ROOT_DN = "{{ldap.dn.root}}" +LDAP_ROOT_DN = "{{ LDAP.DN.ROOT }}" LDAP_USER_ATTR_MAP='{"username":"uid","first_name":"givenName","last_name":"sn","email":"mail"}' {% endif %} diff --git a/roles/web-app-fusiondirectory/templates/env.j2 b/roles/web-app-fusiondirectory/templates/env.j2 index 53057099..0111fec9 100644 --- a/roles/web-app-fusiondirectory/templates/env.j2 +++ b/roles/web-app-fusiondirectory/templates/env.j2 @@ -8,7 +8,7 @@ LAM_PASSWORD= {{ applications | get_app_conf(application_id, 'cred LAM_CONFIGURATION_DATABASE= files # configuration database (files or mysql) @todo implement mariadb # 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.administrator.data}} # LDAP admin user (set as login user for LAM) -LDAP_ADMIN_PASSWORD= {{ldap.bind_credential}} # LDAP admin password \ No newline at end of file +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.ADMINISTRATOR.DATA }} # LDAP admin user (set as login user for LAM) +LDAP_ADMIN_PASSWORD= {{ LDAP.BIND_CREDENTIAL }} # LDAP admin password \ No newline at end of file diff --git a/roles/web-app-gitea/vars/main.yml b/roles/web-app-gitea/vars/main.yml index 5b34667e..f44d6016 100644 --- a/roles/web-app-gitea/vars/main.yml +++ b/roles/web-app-gitea/vars/main.yml @@ -9,18 +9,18 @@ docker_compose_flush_handlers: true # Gitea GITEA_LDAP_AUTH_ARGS: - '--name "LDAP ({{ PRIMARY_DOMAIN }})"' - - '--host "{{ ldap.server.domain }}"' - - '--port {{ ldap.server.port }}' - - '--security-protocol "{{ ldap.server.security | trim or "unencrypted" }}"' - - '--bind-dn "{{ ldap.dn.administrator.data }}"' - - '--bind-password "{{ ldap.bind_credential }}"' - - '--user-search-base "{{ ldap.dn.ou.users }}"' + - '--host "{{ LDAP.SERVER.DOMAIN }}"' + - '--port {{ LDAP.SERVER.PORT }}' + - '--security-protocol "{{ LDAP.SERVER.SECURITY | trim or "unencrypted" }}"' + - '--bind-dn "{{ LDAP.DN.ADMINISTRATOR.DATA }}"' + - '--bind-password "{{ LDAP.BIND_CREDENTIAL }}"' + - '--user-search-base "{{ LDAP.DN.OU.USERS }}"' - '--user-filter "(&(objectClass=inetOrgPerson)(uid=%s))"' - - '--username-attribute "{{ ldap.user.attributes.id }}"' - - '--firstname-attribute "{{ ldap.user.attributes.firstname }}"' - - '--surname-attribute "{{ ldap.user.attributes.surname }}"' - - '--email-attribute "{{ ldap.user.attributes.mail }}"' - - '--public-ssh-key-attribute "{{ ldap.user.attributes.ssh_public_key }}"' + - '--username-attribute "{{ LDAP.USER.ATTRIBUTES.ID }}"' + - '--firstname-attribute "{{ LDAP.USER.ATTRIBUTES.FIRSTNAME }}"' + - '--surname-attribute "{{ LDAP.USER.ATTRIBUTES.SURNAME }}"' + - '--email-attribute "{{ LDAP.USER.ATTRIBUTES.MAIL }}"' + - '--public-ssh-key-attribute "{{ LDAP.USER.ATTRIBUTES.SSH_PUBLIC_KEY }}"' - '--synchronize-users' GITEA_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.gitea.version') }}" GITEA_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.gitea.image') }}" diff --git a/roles/web-app-keycloak/templates/import/components/org.keycloak.storage.UserStorageProvider.json.j2 b/roles/web-app-keycloak/templates/import/components/org.keycloak.storage.UserStorageProvider.json.j2 index 73b2715c..a528ca01 100644 --- a/roles/web-app-keycloak/templates/import/components/org.keycloak.storage.UserStorageProvider.json.j2 +++ b/roles/web-app-keycloak/templates/import/components/org.keycloak.storage.UserStorageProvider.json.j2 @@ -11,7 +11,7 @@ "providerId": "user-attribute-ldap-mapper", "subComponents": {}, "config": { - "ldap.attribute": [ "{{ ldap.user.attributes.firstname }}" ], + "ldap.attribute": [ "{{ LDAP.USER.ATTRIBUTES.FIRSTNAME }}" ], "attribute.force.default": [ "true" ], "is.mandatory.in.ldap": [ "true" ], "is.binary.attribute": [ "false" ], @@ -27,7 +27,7 @@ "providerId": "user-attribute-ldap-mapper", "subComponents": {}, "config": { - "ldap.attribute": [ "{{ ldap.user.attributes.surname }}" ], + "ldap.attribute": [ "{{ LDAP.USER.ATTRIBUTES.SURNAME }}" ], "is.mandatory.in.ldap": [ "true" ], "always.read.value.from.ldap": [ "true" ], "read.only": [ "false" ], @@ -43,7 +43,7 @@ "config": { "read.only": [ "false" ], "write.only": [ "true" ], - "ldap.full.name.attribute": [ "{{ ldap.user.attributes.fullname }}" ] + "ldap.full.name.attribute": [ "{{ LDAP.USER.ATTRIBUTES.FULLNAME }}" ] } }, @@ -53,7 +53,7 @@ "providerId": "user-attribute-ldap-mapper", "subComponents": {}, "config": { - "ldap.attribute": [ "{{ ldap.user.attributes.id }}" ], + "ldap.attribute": [ "{{ LDAP.USER.ATTRIBUTES.ID }}" ], "is.mandatory.in.ldap": [ "true" ], "attribute.force.default": [ "false" ], "is.binary.attribute": [ "false" ], @@ -69,7 +69,7 @@ "providerId": "user-attribute-ldap-mapper", "subComponents": {}, "config": { - "ldap.attribute": [ "{{ ldap.user.attributes.mail }}" ], + "ldap.attribute": [ "{{ LDAP.USER.ATTRIBUTES.MAIL }}" ], "is.mandatory.in.ldap": [ "false" ], "read.only": [ "false" ], "always.read.value.from.ldap": [ "false" ], @@ -83,29 +83,29 @@ "providerId": "user-attribute-ldap-mapper", "subComponents": {}, "config": { - "ldap.attribute": [ "{{ ldap.user.attributes.ssh_public_key }}" ], + "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 }}" ] + "user.model.attribute": [ "{{ LDAP.USER.ATTRIBUTES.SSH_PUBLIC_KEY }}" ] } }, {# ---------------------- Nextcloud Quota ----------------- #} { - "name": "{{ ldap.user.attributes.nextcloud_quota }}", + "name": "{{ LDAP.USER.ATTRIBUTES.NEXTCLOUD_QUOTA }}", "providerId": "user-attribute-ldap-mapper", "subComponents": {}, "config": { - "ldap.attribute": [ "{{ ldap.user.attributes.nextcloud_quota }}" ], + "ldap.attribute": [ "{{ LDAP.USER.ATTRIBUTES.NEXTCLOUD_QUOTA }}" ], "is.mandatory.in.ldap": [ "false" ], "attribute.force.default": [ "false" ], "is.binary.attribute": [ "false" ], "always.read.value.from.ldap": [ "false" ], "read.only": [ "false" ], - "user.model.attribute": [ "{{ ldap.user.attributes.nextcloud_quota }}" ] + "user.model.attribute": [ "{{ LDAP.USER.ATTRIBUTES.NEXTCLOUD_QUOTA }}" ] } }, @@ -145,12 +145,12 @@ "config": { "membership.attribute.type": [ "DN" ], "group.name.ldap.attribute": [ "cn" ], - "membership.user.ldap.attribute": [ "{{ ldap.user.attributes.id }}" ], + "membership.user.ldap.attribute": [ "{{ LDAP.USER.ATTRIBUTES.ID }}" ], "preserve.group.inheritance": [ "true" ], - "groups.dn": [ "{{ ldap.dn.ou.roles }}" ], + "groups.dn": [ "{{ LDAP.DN.OU.ROLES }}" ], "mode": [ "LDAP_ONLY" ], "user.roles.retrieve.strategy": [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ], - "groups.ldap.filter": ["{{ ldap.rbac.flavors | ldap_groups_filter }}"], + "groups.ldap.filter": ["{{ LDAP.RBAC.FLAVORS | ldap_groups_filter }}"], "membership.ldap.attribute": [ "member" ], "ignore.missing.groups": [ "true" ], "group.object.classes": [ "groupOfNames" ], @@ -205,9 +205,9 @@ "mode": [ "LDAP_ONLY" ], "membership.attribute.type": [ "DN" ], "user.roles.retrieve.strategy": [ "LOAD_ROLES_BY_MEMBER_ATTRIBUTE" ], - "roles.dn": [ "{{ ldap.dn.ou.roles }}" ], + "roles.dn": [ "{{ LDAP.DN.OU.ROLES }}" ], "membership.ldap.attribute": [ "member" ], - "membership.user.ldap.attribute": [ "{{ ldap.user.attributes.id }}" ], + "membership.user.ldap.attribute": [ "{{ LDAP.USER.ATTRIBUTES.ID }}" ], "memberof.ldap.attribute": [ "memberOf" ], "role.name.ldap.attribute": [ "cn" ], "use.realm.roles.mapping": [ "true" ], @@ -221,7 +221,7 @@ "pagination": [ "true" ], "connectionTrace": [ "false" ], "startTls": [ "false" ], - "usersDn": [ "{{ ldap.dn.ou.users }}" ], + "usersDn": [ "{{ LDAP.DN.OU.USERS }}" ], "connectionPooling": [ "true" ], "cachePolicy": [ "DEFAULT" ], "useKerberosForPasswordAuthentication": [ "false" ], @@ -229,10 +229,10 @@ "enabled": [ "true" ], "bindCredential": [ "{{ KEYCLOAK_LDAP_BIND_PW }}" ], "changedSyncPeriod": [ "-1" ], - "usernameLDAPAttribute": [ "{{ ldap.user.attributes.id }}" ], + "usernameLDAPAttribute": [ "{{ LDAP.USER.ATTRIBUTES.ID }}" ], "bindDn": [ "{{ KEYCLOAK_LDAP_BIND_DN }}" ], "vendor": [ "other" ], - "uuidLDAPAttribute": [ "{{ ldap.user.attributes.id }}" ], + "uuidLDAPAttribute": [ "{{ LDAP.USER.ATTRIBUTES.ID }}" ], "allowKerberosAuthentication": [ "false" ], "connectionUrl": [ "{{ KEYCLOAK_LDAP_URL }}" ], "syncRegistrations": [ "true" ], @@ -248,7 +248,7 @@ {{ KEYCLOAK_LDAP_USER_OBJECT_CLASSES | trim | tojson }} ], - "rdnLDAPAttribute": [ "{{ ldap.user.attributes.id }}" ], + "rdnLDAPAttribute": [ "{{ LDAP.USER.ATTRIBUTES.ID }}" ], "editMode": [ "WRITABLE" ], "validatePasswordPolicy": [ "false" ], diff --git a/roles/web-app-keycloak/templates/import/components/org.keycloak.userprofile.UserProfileProvider.json.j2 b/roles/web-app-keycloak/templates/import/components/org.keycloak.userprofile.UserProfileProvider.json.j2 index 1109ad7a..8859d90c 100644 --- a/roles/web-app-keycloak/templates/import/components/org.keycloak.userprofile.UserProfileProvider.json.j2 +++ b/roles/web-app-keycloak/templates/import/components/org.keycloak.userprofile.UserProfileProvider.json.j2 @@ -33,7 +33,7 @@ "multivalued": false }, { - "name": ldap.user.attributes.ssh_public_key, + "name": "{{ LDAP.USER.ATTRIBUTES.SSH_PUBLIC_KEY }}", "displayName": "SSH Public Key", "validations": {}, "annotations": {}, diff --git a/roles/web-app-keycloak/templates/import/scopes/nextcloud.json.j2 b/roles/web-app-keycloak/templates/import/scopes/nextcloud.json.j2 index 2d1cfcad..2a83c5a4 100644 --- a/roles/web-app-keycloak/templates/import/scopes/nextcloud.json.j2 +++ b/roles/web-app-keycloak/templates/import/scopes/nextcloud.json.j2 @@ -10,7 +10,7 @@ }, "protocolMappers": [ { - "name": "{{ ldap.user.attributes.nextcloud_quota }}", + "name": "{{ LDAP.USER.ATTRIBUTES.NEXTCLOUD_QUOTA }}", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, @@ -19,11 +19,11 @@ "introspection.token.claim": "true", "multivalued": "false", "userinfo.token.claim": "true", - "user.attribute": "{{ ldap.user.attributes.nextcloud_quota }}", + "user.attribute": "{{ LDAP.USER.ATTRIBUTES.NEXTCLOUD_QUOTA }}", "id.token.claim": "true", "lightweight.claim": "false", "access.token.claim": "true", - "claim.name": "{{ ldap.user.attributes.nextcloud_quota }}", + "claim.name": "{{ LDAP.USER.ATTRIBUTES.NEXTCLOUD_QUOTA }}", "jsonType.label": "int" } }, @@ -41,7 +41,7 @@ "id.token.claim": "true", "lightweight.claim": "false", "access.token.claim": "true", - "claim.name": "{{ldap.user.attributes.id}}", + "claim.name": "{{LDAP.USER.ATTRIBUTES.ID}}", "jsonType.label": "String" } } diff --git a/roles/web-app-keycloak/vars/main.yml b/roles/web-app-keycloak/vars/main.yml index aee077ad..cebb4344 100644 --- a/roles/web-app-keycloak/vars/main.yml +++ b/roles/web-app-keycloak/vars/main.yml @@ -55,17 +55,17 @@ KEYCLOAK_POST_LOGOUT_URIS: "+" ## LDAP KEYCLOAK_LDAP_ENABLED: "{{ applications | get_app_conf(application_id, 'features.ldap', False) }}" -KEYCLOAK_LDAP_CMP_NAME: "{{ ldap.server.domain }}" # Name of the LDAP User Federation component in Keycloak (as shown in UI) -KEYCLOAK_LDAP_BIND_DN: "{{ ldap.dn.administrator.data }}" -KEYCLOAK_LDAP_BIND_PW: "{{ ldap.bind_credential }}" -KEYCLOAK_LDAP_URL: "{{ ldap.server.uri }}" +KEYCLOAK_LDAP_CMP_NAME: "{{ LDAP.SERVER.DOMAIN }}" # Name of the LDAP User Federation component in Keycloak (as shown in UI) +KEYCLOAK_LDAP_BIND_DN: "{{ LDAP.DN.ADMINISTRATOR.DATA }}" +KEYCLOAK_LDAP_BIND_PW: "{{ LDAP.BIND_CREDENTIAL }}" +KEYCLOAK_LDAP_URL: "{{ LDAP.SERVER.URI }}" # It's important to filter the posixAccount class out, because it is just used by ansible KEYCLOAK_LDAP_USER_OBJECT_CLASSES: > {{ ( - (ldap.user.objects.structural | reject('equalto','posixAccount') | list) - + (ldap.user.objects.auxiliary | dict2items | map(attribute='value') | list) + (LDAP.USER.OBJECTS.STRUCTURAL | reject('equalto','posixAccount') | list) + + (LDAP.USER.OBJECTS.AUXILIARY | dict2items | map(attribute='value') | list) ) | join(', ') }} diff --git a/roles/web-app-lam/templates/env.j2 b/roles/web-app-lam/templates/env.j2 index 53057099..ff16566d 100644 --- a/roles/web-app-lam/templates/env.j2 +++ b/roles/web-app-lam/templates/env.j2 @@ -8,7 +8,7 @@ LAM_PASSWORD= {{ applications | get_app_conf(application_id, 'cred LAM_CONFIGURATION_DATABASE= files # configuration database (files or mysql) @todo implement mariadb # 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.administrator.data}} # LDAP admin user (set as login user for LAM) -LDAP_ADMIN_PASSWORD= {{ldap.bind_credential}} # LDAP admin password \ No newline at end of file +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.ADMINISTRATOR.DATA }} # LDAP admin user (set as login user for LAM) +LDAP_ADMIN_PASSWORD= {{ LDAP.BIND_CREDENTIAL }} # LDAP admin password \ No newline at end of file diff --git a/roles/web-app-nextcloud/tasks/plugins/user_ldap.yml b/roles/web-app-nextcloud/tasks/plugins/user_ldap.yml index 14be2541..8ba63e90 100644 --- a/roles/web-app-nextcloud/tasks/plugins/user_ldap.yml +++ b/roles/web-app-nextcloud/tasks/plugins/user_ldap.yml @@ -3,7 +3,7 @@ - name: Set Nextcloud LDAP bind password command: > - {{ NEXTCLOUD_DOCKER_EXEC_OCC }} ldap:set-config s01 ldapAgentPassword "{{ ldap.bind_credential }}" + {{ NEXTCLOUD_DOCKER_EXEC_OCC }} ldap:set-config s01 ldapAgentPassword "{{ LDAP.BIND_CREDENTIAL }}" async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}" poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" \ No newline at end of file diff --git a/roles/web-app-nextcloud/templates/config/oidc.config.php.j2 b/roles/web-app-nextcloud/templates/config/oidc.config.php.j2 index a251a3ea..64a6979b 100644 --- a/roles/web-app-nextcloud/templates/config/oidc.config.php.j2 +++ b/roles/web-app-nextcloud/templates/config/oidc.config.php.j2 @@ -97,10 +97,10 @@ return array ( // note: on Keycloak, OIDC name claim = "${given_name} ${family_name}" or one of them if any is missing // 'oidc_login_attributes' => array ( - 'id' => '{{ldap.user.attributes.id}}', + 'id' => '{{LDAP.USER.ATTRIBUTES.ID}}', 'name' => 'name', 'mail' => 'email', - 'quota' => '{{ ldap.user.attributes.nextcloud_quota }}', + 'quota' => '{{ LDAP.USER.ATTRIBUTES.NEXTCLOUD_QUOTA }}', # 'home' => 'homeDirectory', # Not implemented yet 'ldap_uid' => '{{ OIDC.ATTRIBUTES.USERNAME }}', # 'groups' => 'ownCloudGroups', # Not implemented yet diff --git a/roles/web-app-nextcloud/vars/plugins/user_ldap.yml b/roles/web-app-nextcloud/vars/plugins/user_ldap.yml index e94e8ba4..87ce7cac 100644 --- a/roles/web-app-nextcloud/vars/plugins/user_ldap.yml +++ b/roles/web-app-nextcloud/vars/plugins/user_ldap.yml @@ -32,17 +32,17 @@ plugin_configuration: - appid: "user_ldap" configkey: "s01ldap_base" - configvalue: "{{ldap.dn.root}}" + configvalue: "{{ LDAP.DN.ROOT }}" - appid: "user_ldap" configkey: "s01ldap_base_groups" - configvalue: "{{ldap.dn.root}}" + configvalue: "{{ LDAP.DN.ROOT }}" - appid: "user_ldap" configkey: "s01ldap_base_users" - configvalue: "{{ldap.dn.ou.users}}" + configvalue: "{{LDAP.DN.OU.USERS}}" - appid: "user_ldap" @@ -67,7 +67,7 @@ plugin_configuration: - appid: "user_ldap" configkey: "s01ldap_dn" - configvalue: "{{ldap.dn.administrator.data}}" + configvalue: "{{LDAP.DN.ADMINISTRATOR.DATA}}" - appid: "user_ldap" configkey: "s01ldap_email_attr" @@ -103,11 +103,11 @@ plugin_configuration: - appid: "user_ldap" configkey: "s01ldap_host" - configvalue: "{{ldap.server.domain}}" + configvalue: "{{ LDAP.SERVER.DOMAIN }}" - appid: "user_ldap" configkey: "s01ldap_login_filter" - configvalue: "{{ ldap.filters.users.login }}" + configvalue: "{{ LDAP.FILTERS.USERS.LOGIN }}" - appid: "user_ldap" configkey: "s01ldap_login_filter_mode" @@ -165,7 +165,7 @@ plugin_configuration: configkey: "s01ldap_userlist_filter" configvalue: |- {% if applications | get_app_conf(application_id, 'plugins.user_ldap.user_directory.enabled', True) %} - {{ ldap.filters.users.all }} + {{ LDAP.FILTERS.USERS.ALL }} {% else %} () {% endif %} @@ -181,4 +181,4 @@ plugin_configuration: - appid: "user_ldap" configkey: "s01ldap_expert_username_attr" - configvalue: "{{ldap.user.attributes.id}}" \ No newline at end of file + configvalue: "{{LDAP.USER.ATTRIBUTES.ID}}" \ No newline at end of file diff --git a/roles/web-app-openproject/vars/ldap.yml b/roles/web-app-openproject/vars/ldap.yml index b1f53d2a..c2e6a969 100644 --- a/roles/web-app-openproject/vars/ldap.yml +++ b/roles/web-app-openproject/vars/ldap.yml @@ -1,14 +1,14 @@ openproject_ldap: name: "{{ PRIMARY_DOMAIN }}" # Display name for the LDAP connection in OpenProject - host: "{{ ldap.server.domain }}" # LDAP server address - port: "{{ ldap.server.port }}" # LDAP server port (typically 389 or 636) - account: "{{ ldap.dn.administrator.data }}" # Bind DN (used for authentication) - account_password: "{{ ldap.bind_credential }}" # Bind password - base_dn: "{{ ldap.dn.ou.users }}" # Base DN for user search - attr_login: "{{ ldap.user.attributes.id }}" # LDAP attribute used for login + host: "{{ LDAP.SERVER.DOMAIN }}" # LDAP server address + port: "{{ LDAP.SERVER.PORT }}" # LDAP server port (typically 389 or 636) + account: "{{ LDAP.DN.ADMINISTRATOR.DATA }}" # Bind DN (used for authentication) + account_password: "{{ LDAP.BIND_CREDENTIAL }}" # Bind password + base_dn: "{{ LDAP.DN.OU.USERS }}" # Base DN for user search + attr_login: "{{ LDAP.USER.ATTRIBUTES.ID }}" # LDAP attribute used for login attr_firstname: "givenName" # LDAP attribute for first name - attr_lastname: "{{ ldap.user.attributes.surname }}" # LDAP attribute for last name - attr_mail: "{{ ldap.user.attributes.mail }}" # LDAP attribute for email + attr_lastname: "{{ LDAP.USER.ATTRIBUTES.SURNAME }}" # LDAP attribute for last name + 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) onthefly_register: true # Automatically create users on first login tls_mode: 0 # 0 = No TLS, 1 = TLS, 2 = STARTTLS diff --git a/roles/web-app-openproject/vars/main.yml b/roles/web-app-openproject/vars/main.yml index bfac4431..1273df1d 100644 --- a/roles/web-app-openproject/vars/main.yml +++ b/roles/web-app-openproject/vars/main.yml @@ -5,17 +5,17 @@ application_id: "web-app-openproject" database_type: "postgres" # Open Project Specific -openproject_version: "{{ applications | get_app_conf(application_id, 'docker.services.web.version', True) }}" -openproject_image: "{{ applications | get_app_conf(application_id, 'docker.services.web.image', True) }}" -openproject_volume: "{{ applications | get_app_conf(application_id, 'docker.volumes.data', True) }}" -openproject_web_name: "{{ applications | get_app_conf(application_id, 'docker.services.web.name', True) }}" -openproject_seeder_name: "{{ applications | get_app_conf(application_id, 'docker.services.seeder.name', True) }}" -openproject_cron_name: "{{ applications | get_app_conf(application_id, 'docker.services.cron.name', True) }}" -openproject_proxy_name: "{{ applications | get_app_conf(application_id, 'docker.services.proxy.name', True) }}" -openproject_worker_name: "{{ applications | get_app_conf(application_id, 'docker.services.worker.name', True) }}" +openproject_version: "{{ applications | get_app_conf(application_id, 'docker.services.web.version') }}" +openproject_image: "{{ applications | get_app_conf(application_id, 'docker.services.web.image') }}" +openproject_volume: "{{ applications | get_app_conf(application_id, 'docker.volumes.data') }}" +openproject_web_name: "{{ applications | get_app_conf(application_id, 'docker.services.web.name') }}" +openproject_seeder_name: "{{ applications | get_app_conf(application_id, 'docker.services.seeder.name') }}" +openproject_cron_name: "{{ applications | get_app_conf(application_id, 'docker.services.cron.name') }}" +openproject_proxy_name: "{{ applications | get_app_conf(application_id, 'docker.services.proxy.name') }}" +openproject_worker_name: "{{ applications | get_app_conf(application_id, 'docker.services.worker.name') }}" # Open Project Cache -openproject_cache_name: "{{ applications | get_app_conf(application_id, 'docker.services.cache.name', True) }}" +openproject_cache_name: "{{ applications | get_app_conf(application_id, 'docker.services.cache.name') }}" openproject_cache_image: "{{ applications | get_app_conf(application_id, 'docker.services.cache.image') or applications @@ -45,11 +45,11 @@ openproject_rails_settings: smtp_ssl: false openproject_filters: - administrators: "{{ '(memberOf=cn=openproject-admins,' ~ ldap.dn.ou.roles ~ ')' - if applications | get_app_conf(application_id, 'ldap.filters.administrators', True) else '' }}" + administrators: "{{ '(memberOf=cn=openproject-admins,' ~ LDAP.DN.OU.ROLES ~ ')' + if applications | get_app_conf(application_id, 'ldap.filters.administrators') else '' }}" - users: "{{ '(memberOf=cn=openproject-users,' ~ ldap.dn.ou.roles ~ ')' - if applications | get_app_conf(application_id, 'ldap.filters.users', True) else '' }}" + users: "{{ '(memberOf=cn=openproject-users,' ~ LDAP.DN.OU.ROLES ~ ')' + if applications | get_app_conf(application_id, 'ldap.filters.users') else '' }}" # Docker docker_repository_branch: "stable/{{ openproject_version }}" diff --git a/roles/web-app-phpldapadmin/templates/env.j2 b/roles/web-app-phpldapadmin/templates/env.j2 index cad768fe..07b5500b 100644 --- a/roles/web-app-phpldapadmin/templates/env.j2 +++ b/roles/web-app-phpldapadmin/templates/env.j2 @@ -1,3 +1,3 @@ # @See https://github.com/leenooks/phpLDAPadmin/wiki/Docker-Container APP_URL= {{ domains | get_url(application_id, WEB_PROTOCOL) }} -LDAP_HOST= {{ldap.server.domain}} \ No newline at end of file +LDAP_HOST= {{ LDAP.SERVER.DOMAIN }} \ No newline at end of file diff --git a/roles/web-app-snipe-it/tasks/ldap.yml b/roles/web-app-snipe-it/tasks/ldap.yml index ddbae533..f32efbe0 100644 --- a/roles/web-app-snipe-it/tasks/ldap.yml +++ b/roles/web-app-snipe-it/tasks/ldap.yml @@ -21,21 +21,21 @@ sh -c 'php artisan tinker << "EOF" $s = \App\Models\Setting::getSettings(); $s->ldap_enabled = 1; - $s->ldap_server = "{{ ldap.server.uri }}"; - $s->ldap_port = {{ ldap.server.port }}; - $s->ldap_uname = "{{ ldap.dn.administrator.data }}"; - $s->ldap_basedn = "{{ ldap.dn.ou.users }}"; + $s->ldap_server = "{{ LDAP.SERVER.URI }}"; + $s->ldap_port = {{ LDAP.SERVER.PORT }}; + $s->ldap_uname = "{{ LDAP.DN.ADMINISTRATOR.DATA }}"; + $s->ldap_basedn = "{{ LDAP.DN.OU.USERS }}"; $s->ldap_filter = "&(objectClass=inetOrgPerson)"; - $s->ldap_username_field = "{{ ldap.user.attributes.id }}"; - $s->ldap_fname_field = "{{ ldap.user.attributes.firstname }}"; - $s->ldap_lname_field = "{{ ldap.user.attributes.surname }}"; + $s->ldap_username_field = "{{ LDAP.USER.ATTRIBUTES.ID }}"; + $s->ldap_fname_field = "{{ LDAP.USER.ATTRIBUTES.FIRSTNAME }}"; + $s->ldap_lname_field = "{{ LDAP.USER.ATTRIBUTES.SURNAME }}"; $s->ldap_auth_filter_query = "uid="; $s->ldap_version = 3; $s->ldap_pw_sync = 0; $s->is_ad = 0; $s->ad_domain = ""; $s->ldap_default_group = ""; - $s->ldap_email = "{{ ldap.user.attributes.mail }}"; + $s->ldap_email = "{{ LDAP.USER.ATTRIBUTES.MAIL }}"; $s->custom_forgot_pass_url = "{{ OIDC.CLIENT.RESET_CREDENTIALS }}"; $s->save(); EOF' @@ -62,7 +62,7 @@ use Illuminate\Support\Facades\DB; /* encrypt the clear-text password */ - \$encrypted = Crypt::encrypt('{{ ldap.bind_credential }}'); + \$encrypted = Crypt::encrypt('{{ LDAP.BIND_CREDENTIAL }}'); /* write it straight into settings.ldap_pword */ /* update the one and only row in `settings` */ diff --git a/tests/integration/test_uppercase_constant_vars_unique.py b/tests/integration/test_uppercase_constant_vars_unique.py index 97a37a47..77fbe6d5 100644 --- a/tests/integration/test_uppercase_constant_vars_unique.py +++ b/tests/integration/test_uppercase_constant_vars_unique.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -Integration test: ensure every ALL-CAPS variable is defined only once project-wide. +Integration test: ensure every TOP-LEVEL ALL-CAPS variable is defined only once project-wide. Scope (by design): - group_vars/**/*.yml @@ -8,9 +8,11 @@ Scope (by design): - roles/*/defaults/*.yml - roles/*/defauls/*.yml # included on purpose in case of folder typos -A variable is considered a “constant” if its key matches: ^[A-Z0-9_]+$ -If a constant is declared more than once across the scanned files, the test fails -with a clear message explaining that such constants must be defined only once. +A variable is considered a “constant” if its KEY (at the top level of a YAML document) +matches: ^[A-Z0-9_]+$ + +Only TOP-LEVEL keys are checked for uniqueness. Nested keys are ignored to allow +namespacing like DICTIONARYA.ENTRY and DICTIONARYB.ENTRY without conflicts. """ import os @@ -41,42 +43,32 @@ def _iter_yaml_files(): seen = set() for pattern in patterns: for path in glob.glob(pattern, recursive=True): - # Normalize and deduplicate norm = os.path.normpath(path) if norm not in seen and os.path.isfile(norm): seen.add(norm) yield norm -def _extract_uppercase_keys_from_mapping(mapping): +def _extract_top_level_uppercase_keys(docs): """ - Recursively extract ALL-CAPS keys from any YAML mapping. - Returns a set of keys found in this mapping (deduplicated for the file). + Return a set of TOP-LEVEL ALL-CAPS keys found across all mapping documents in a file. + Nested keys are intentionally ignored. """ found = set() - - def walk(node): - if isinstance(node, dict): - for k, v in node.items(): - # Only consider string keys + for doc in docs: + if isinstance(doc, dict): + for k in doc.keys(): if isinstance(k, str) and UPPER_CONST_RE.match(k): found.add(k) - # Recurse into values to catch nested mappings too - walk(v) - elif isinstance(node, list): - for item in node: - walk(item) - - walk(mapping) return found class TestUppercaseConstantVarsUnique(unittest.TestCase): def test_uppercase_constants_unique(self): - # Track where each constant is defined + # Track where each TOP-LEVEL constant is defined constant_to_files = defaultdict(set) - # Track YAML parse errors to fail fast with a helpful message + # Track YAML parse errors to fail with a helpful message parse_errors = [] yaml_files = list(_iter_yaml_files()) @@ -88,35 +80,32 @@ class TestUppercaseConstantVarsUnique(unittest.TestCase): parse_errors.append(f"{yml}: {e}") continue - # Some files may be empty or contain only comments if not docs: continue - # Collect ALL-CAPS keys for this file (dedup per file) - file_constants = set() - for doc in docs: - if isinstance(doc, dict): - file_constants |= _extract_uppercase_keys_from_mapping(doc) - # Non-mapping documents (e.g., lists/None) are ignored + file_constants = _extract_top_level_uppercase_keys(docs) for const in file_constants: constant_to_files[const].add(yml) - # Fail if YAML parsing had errors if parse_errors: self.fail( "YAML parsing failed for one or more files:\n" + "\n".join(f"- {err}" for err in parse_errors) ) - # Find duplicates (same constant in more than one file) - duplicates = {c: sorted(files) for c, files in constant_to_files.items() if len(files) > 1} + # Duplicates are same TOP-LEVEL constant appearing in >1 files + duplicates = { + c: sorted(files) + for c, files in constant_to_files.items() + if len(files) > 1 + } if duplicates: msg_lines = [ - "Found constants defined more than once. " - "ALL-CAPS variables are treated as constants and must be defined only once project-wide.\n" - "Please consolidate each duplicated constant into a single authoritative location (e.g., one vars/defaults file).", + "Found TOP-LEVEL constants defined more than once. " + "ALL-CAPS top-level variables are treated as constants and must be defined only once project-wide.\n" + "Nested ALL-CAPS keys are allowed and ignored by this test.", "", ] for const, files in sorted(duplicates.items()): diff --git a/tests/unit/roles/svc-db-openldap/test_build_ldap_role_entries.py b/tests/unit/roles/svc-db-openldap/test_build_ldap_role_entries.py index 193c4300..f776d384 100644 --- a/tests/unit/roles/svc-db-openldap/test_build_ldap_role_entries.py +++ b/tests/unit/roles/svc-db-openldap/test_build_ldap_role_entries.py @@ -42,19 +42,19 @@ class TestBuildLdapRoleEntries(unittest.TestCase): } self.ldap = { - "dn": { - "ou": { - "users": "ou=users,dc=example,dc=org", - "roles": "ou=roles,dc=example,dc=org" + "DN": { + "OU": { + "USERS": "ou=users,dc=example,dc=org", + "ROLES": "ou=roles,dc=example,dc=org" } }, - "user":{ - "attributes": { - "id": "uid" + "USER":{ + "ATTRIBUTES": { + "ID": "uid" } }, - "rbac": { - "flavors": ["posixGroup", "groupOfNames"] + "RBAC": { + "FLAVORS": ["posixGroup", "groupOfNames"] } }