From e9b5475a39acf720754ef8589195c2d19aab4a20 Mon Sep 17 00:00:00 2001 From: transcaffeine Date: Sat, 16 Oct 2021 15:01:14 +0200 Subject: [PATCH] feat(ldap-user-backend): add role for managing ldap user backend in nextcloud --- galaxy.yml | 2 + roles/ldap-user-backend/README.md | 27 ++++++++ roles/ldap-user-backend/defaults/main.yml | 66 ++++++++++++++++++ roles/ldap-user-backend/meta/main.yml | 4 ++ roles/ldap-user-backend/tasks/main.yml | 81 +++++++++++++++++++++++ roles/ldap-user-backend/vars/main.yml | 60 +++++++++++++++++ 6 files changed, 240 insertions(+) create mode 100644 roles/ldap-user-backend/README.md create mode 100644 roles/ldap-user-backend/defaults/main.yml create mode 100644 roles/ldap-user-backend/meta/main.yml create mode 100644 roles/ldap-user-backend/tasks/main.yml create mode 100644 roles/ldap-user-backend/vars/main.yml diff --git a/galaxy.yml b/galaxy.yml index c45c8bc..706b0f1 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -5,6 +5,8 @@ readme: README.md authors: - Johanna Dorothea Reichmann description: Installing and configuring nextcloud (and related apps/services) using docker +dependencies: + "community.docker": "^1.10.0" license: - CNPLv7+ build_ignore: diff --git a/roles/ldap-user-backend/README.md b/roles/ldap-user-backend/README.md new file mode 100644 index 0000000..1122f28 --- /dev/null +++ b/roles/ldap-user-backend/README.md @@ -0,0 +1,27 @@ +# `finallycoffee.nextcloud.ldap-user-backend` ansible role + +Ansible role for managing LDAP authentication of nextcloud instances using ansible. + +## Prerequisites + +This role assumes a nextcloud instance is up and running, and has the `user_ldap` +nextcloud app installed. For starting a nextcloud instance, see the +`finallycoffee.nextcloud.server` role, for managing nextcloud apps see the +`finallycoffee.nextcloud.apps` ansible role. + +## Configuration + +- Set `nc_ldap_api_method` to either `occ` or `http` to control wether the + configuration is set using `php occ` command line calls or the `http` API + of the `user_ldap` nextcloud app. + +- For `nc_ldap_api_method: occ`, ensure `nc_ldap_container` is set to the name + of the docker container where nextcloud is running, and `nc_ldap_occ_user` is + the user the container / nextcloud itself runs as. `nc_ldap_occ_command` + _can_ also be tweaked if `php` is not in the path, but the default should + be fine in most cases. + +- For `nc_ldap_api_method: http`, ensure `nc_ldapi_api_instance_url` contains + the URL to the nextcloud server, including protocol (and port, if + non-standard), and `nc_ldap_api_basic_auth_[user|password]` contain the + credentials of an admin user with the rights to edit the LDAP settings. diff --git a/roles/ldap-user-backend/defaults/main.yml b/roles/ldap-user-backend/defaults/main.yml new file mode 100644 index 0000000..c4f03be --- /dev/null +++ b/roles/ldap-user-backend/defaults/main.yml @@ -0,0 +1,66 @@ +--- + +nc_ldap_api_method: occ + +nc_ldap_api_instance_url: http://localhost +nc_ldap_api_basic_auth_user: +nc_ldap_api_basic_auth_password: + +nc_ldap_occ_command: "php occ" +nc_ldap_occ_user: "nextcloud" +nc_ldap_container: nextcloud + +nc_ldap_config_id: s01 +nc_ldap_config_host: 127.0.0.1 +nc_ldap_config_port: 389 +nc_ldap_config_backup_host: ~ +nc_ldap_config_backup_port: ~ + +nc_ldap_config_base_dn: +nc_ldap_config_base_dn_users: +nc_ldap_config_base_dn_groups: +nc_ldap_config_agent_name: +nc_ldap_config_agent_password: + +nc_ldap_config_override_main_server: ~ +nc_ldap_config_tls: ~ +nc_ldap_config_turn_off_cert_check: ~ +nc_ldap_config_user_displayname: ~ +nc_ldap_config_user_displayname2: ~ +nc_ldap_config_user_avatar_rule: ~ +nc_ldap_config_gid_number: ~ +nc_ldap_config_user_filter_objectclass: ~ +nc_ldap_config_user_filter_groups: ~ +nc_ldap_config_user_filter: ~ +nc_ldap_config_user_filter_mode: ~ +nc_ldap_config_attributes_for_user_search: ~ +nc_ldap_config_group_filter: ~ +nc_ldap_config_group_filter_mode: ~ +nc_ldap_config_group_filter_objectclass: ~ +nc_ldap_config_group_filter_groups: ~ +nc_ldap_config_group_member_assoc_attr: ~ +nc_ldap_config_group_displayname: ~ +nc_ldap_config_attributes_for_group_search: ~ +nc_ldap_config_login_filter: ~ +nc_ldap_config_login_filter_mode: ~ +nc_ldap_config_login_filter_email: ~ +nc_ldap_config_login_filter_username: ~ +nc_ldap_config_login_filter_attributes: ~ +nc_ldap_config_quota_attribute: ~ +nc_ldap_config_quota_default: ~ +nc_ldap_config_email_attribute: ~ +nc_ldap_config_cache_ttl: ~ +nc_ldap_config_configuration_active: ~ +nc_ldap_config_experienced_admin: ~ +nc_ldap_config_home_folder_naming_rule: ~ +nc_ldap_config_use_memberOf_to_detect_membership: ~ +nc_ldap_config_expert_username_attr: ~ +nc_ldap_config_expert_uuid_user_attr: ~ +nc_ldap_config_expert_uuid_group_attr: ~ +nc_ldap_config_nested_groups: ~ +nc_ldap_config_paging_size: ~ +nc_ldap_config_turn_on_password_change: ~ +nc_ldap_config_dynamic_group_member_url: ~ +nc_ldap_config_default_ppolicy_dn: ~ + +nc_ldap_meta_http_agent: "ansible-httpget/finallycoffee.nextcloud.ldap-user-backend" diff --git a/roles/ldap-user-backend/meta/main.yml b/roles/ldap-user-backend/meta/main.yml new file mode 100644 index 0000000..ec33810 --- /dev/null +++ b/roles/ldap-user-backend/meta/main.yml @@ -0,0 +1,4 @@ +--- + +collections: + - community.docker diff --git a/roles/ldap-user-backend/tasks/main.yml b/roles/ldap-user-backend/tasks/main.yml new file mode 100644 index 0000000..e2dec88 --- /dev/null +++ b/roles/ldap-user-backend/tasks/main.yml @@ -0,0 +1,81 @@ +--- + +- name: Set default api parameters for HTTP + meta: noop + vars: &api_defaults + http_agent: "{{ nc_ldap_meta_http_agent }}" + headers: "{{ nc_ldap_api_headers }}" + url_username: "{{ nc_ldap_api_basic_auth_user }}" + url_password: "{{ nc_ldap_api_basic_auth_password }}" + force_basic_auth: yes + force: yes + when: nc_ldap_api_method == 'http' + +- name: Check if configuration with given config ID already exists (occ) + docker_container_exec: + container: "{{ nc_ldap_container }}" + command: "{{ nc_ldap_occ_command }} ldap:show-config --output json {{ '--show-password' if nc_ldap_config_agent_password else '' }} {{ nc_ldap_config_id }}" + user: "{{ nc_ldap_occ_user }}" + tty: yes + when: nc_ldap_api_method == 'occ' + changed_when: false + check_mode: false + register: nc_ldap_existing_config_occ + +- name: Check if configuration with given config ID already exists (http) + uri: + <<: *api_defaults + url: "{{ nc_ldap_api_path }}/{{ nc_ldap_config_id }}{{ query_params }}" + method: GET + vars: + query_params: "?showPassword={{ '1' if nc_ldap_config_agent_password else '0' }}&format={{nc_ldap_api_parameter_format }}" + when: nc_ldap_api_method == 'http' + register: nc_ldap_existing_config_api + +# TODO: Can we force an ID on POST? +- name: Create ldap configuration with id={{ nc_ldap_config_id }} (http) + uri: + <<: *api_defaults + url: "{{ nc_ldap_api_path }}" + method: POST + when: nc_ldap_api_method == 'http' and nc_ldap_existing_config_api.status != 200 + +- name: Create ldap configuration with id={{ nc_ldap_config_id }} (occ) + docker_container_exec: + container: "{{ nc_ldap_container }}" + command: "{{ nc_ldap_occ_command }} ldap:create-empty-config --output json {{ nc_ldap_config_id }}" + user: "{{ nc_ldap_occ_user }}" + tty: yes + when: nc_ldap_api_method == 'occ' and nc_ldap_existing_config_occ.rc != 0 and nc_ldap_config_id not in (nc_ldap_existing_config_occ.stdout | from_json).keys() + +- name: Parse output of query command to dict + set_fact: + nc_ldap_existing_config: "{{ nc_ldap_existing_config_occ.stdout | from_json }}" + changed_when: false + +- name: Create changeset + set_fact: + nc_ldap_config_changeset: "{{ nc_ldap_config_changeset | combine(changed_entry) }}" + vars: + changed_entry: "{{ { item : nc_ldap_config_keys[item] } }}" + loop: "{{ nc_ldap_config_keys.keys() }}" + when: nc_ldap_config_keys[item] is defined and nc_ldap_config_keys[item] and nc_ldap_config_keys[item] != nc_ldap_existing_config[nc_ldap_config_id][item] + +- name: Ensure ldap configuration is in sync (http) + uri: + <<: *api_defaults + url: + method: PUT + body: + body_format: "form-urlencoded" + loop: "{{ nc_ldap_config_changeset | dict2items }}" + when: nc_ldap_api_method == 'http' + +- name: Ensure ldap configuration is in sync (occ) + docker_container_exec: + container: "{{ nc_ldap_container }}" + command: "{{ nc_ldap_occ_command }} ldap:set-config \"{{ nc_ldap_config_id }}\" \"{{ item.key }}\" \"{{ item.value }}\"" + user: "{{ nc_ldap_occ_user }}" + tty: yes + loop: "{{ nc_ldap_config_changeset | dict2items }}" + when: nc_ldap_api_method == 'occ' diff --git a/roles/ldap-user-backend/vars/main.yml b/roles/ldap-user-backend/vars/main.yml new file mode 100644 index 0000000..8154f0f --- /dev/null +++ b/roles/ldap-user-backend/vars/main.yml @@ -0,0 +1,60 @@ +--- + +nc_ldap_api_path: "/ocs/v2.php/apps/user_ldap/api/v1/config" +nc_ldap_api_url: "{{ nc_ldap_api_instance_url }}{{ nc_ldap_api_path }}" +nc_ldap_api_headers: + OCS-APIREQUEST: "true" +nc_ldap_api_parameter_format: json + +nc_ldap_config_keys: + ldapHost: "{{ nc_ldap_config_host }}" + ldapPort: "{{ nc_ldap_config_port }}" + ldapBackupHost: "{{ nc_ldap_config_backup_host }}" + ldapBackupPort: "{{ nc_ldap_config_backup_port }}" + ldapOverrideMainServer: "{{ nc_ldap_config_override_main_server }}" + ldapBase: "{{ nc_ldap_config_base_dn }}" + ldapBaseUsers: "{{ nc_ldap_config_base_dn_users }}" + ldapBaseGroups: "{{ nc_ldap_config_base_dn_groups }}" + ldapAgentName: "{{ nc_ldap_config_agent_name }}" + ldapAgentPassword: "{{ nc_ldap_config_agent_password }}" + ldapTLS: "{{ nc_ldap_config_tls }}" + turnOffCertCheck: "{{ nc_ldap_config_turn_off_cert_check }}" + ldapUserDisplayName: "{{ nc_ldap_config_user_displayname }}" + ldapUserDisplayName2: "{{ nc_ldap_config_user_displayname2 }}" + ldapUserAvatarRule: "{{ nc_ldap_config_user_avatar_rule }}" + ldapGidNumber: "{{ nc_ldap_config_gid_number }}" + ldapUserFilterObjectclass: "{{ nc_ldap_config_user_filter_objectclass }}" + ldapUserFilterGroups: "{{ nc_ldap_config_user_filter_groups }}" + ldapUserFilter: "{{ nc_ldap_config_user_filter }}" + ldapUserFilterMode: "{{ nc_ldap_config_user_filter_mode }}" + ldapAttributesForUserSearch: "{{ nc_ldap_config_attributes_for_user_search }}" + ldapGroupFilter: "{{ nc_ldap_config_group_filter }}" + ldapGroupFilterMode: "{{ nc_ldap_config_group_filter_mode }}" + ldapGroupFilterObjectclass: "{{ nc_ldap_config_group_filter_objectclass }}" + ldapGroupFilterGroups: "{{ nc_ldap_config_group_filter_groups }}" + ldapGroupMemberAssocAttr: "{{ nc_ldap_config_group_member_assoc_attr }}" + ldapGroupDisplayName: "{{ nc_ldap_config_group_displayname }}" + ldapAttributesForGroupSearch: "{{ nc_ldap_config_attributes_for_group_search }}" + ldapLoginFilter: "{{ nc_ldap_config_login_filter }}" + ldapLoginFilterMode: "{{ nc_ldap_config_login_filter_mode }}" + ldapLoginFilterEmail: "{{ nc_ldap_config_login_filter_email }}" + ldapLoginFilterUsername: "{{ nc_ldap_config_login_filter_username }}" + ldapLoginFilterAttributes: "{{ nc_ldap_config_login_filter_attributes }}" + ldapQuotaAttribute: "{{ nc_ldap_config_quota_attribute }}" + ldapQuotaDefault: "{{ nc_ldap_config_quota_default }}" + ldapEmailAttribute: "{{ nc_ldap_config_email_attribute }}" + ldapCacheTTL: "{{ nc_ldap_config_cache_ttl }}" + ldapConfigurationActive: "{{ nc_ldap_config_configuration_active }}" + ldapExperiencedAdmin: "{{ nc_ldap_config_experienced_admin }}" + homeFolderNamingRule: "{{ nc_ldap_config_home_folder_naming_rule }}" + useMemberOfToDetectMembership: "{{ nc_ldap_config_use_memberOf_to_detect_membership }}" + ldapExpertUsernameAttr: "{{ nc_ldap_config_expert_username_attr }}" + ldapExpertUUIDUserAttr: "{{ nc_ldap_config_expert_uuid_user_attr }}" + ldapExpertUUIDGroupAttr: "{{ nc_ldap_config_expert_uuid_group_attr }}" + ldapNestedGroups: "{{ nc_ldap_config_nested_groups }}" + ldapPagingSize: "{{ nc_ldap_config_paging_size }}" + turnOnPasswordChange: "{{ nc_ldap_config_turn_on_password_change }}" + ldapDynamicGroupMemberURL: "{{ nc_ldap_config_dynamic_group_member_url }}" + ldapDefaultPPolicyDN: "{{ nc_ldap_config_default_ppolicy_dn }}" + +nc_ldap_config_changeset: {}