diff --git a/README.md b/README.md index 428c73f..3248d3b 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ and managing nextcloud installations server instance. Can install, remove, enable/disable and update apps. - [`ldap_user_backend`](roles/ldap_user_backend/README.md): Manages LDAP authentication sources in installed nextcloud instances. +- [`oidc_user_backend`](roles/oidc_user_backend/README.md): + Manage OIDC authentication sources in installed nextcloud instances. - [`nginx_fpm_proxy`](roles/nginx_fpm_proxy/README.md): Reverse proxy role which connects to nextcloud using FPM and serves static content. diff --git a/roles/oidc_user_backend/README.md b/roles/oidc_user_backend/README.md new file mode 100644 index 0000000..a6c663d --- /dev/null +++ b/roles/oidc_user_backend/README.md @@ -0,0 +1,29 @@ +# `finallycoffee.nextcloud.oidc_user_backend` ansible role + +Configure OIDC user backends in nextcloud using this ansible role. +This role can be run multiple times with different arguments in order to +configure multiple oidc-based user backends. + +> [!WARNING] +> This role is not production ready or finished + +## Configuration + +Set `oidc_user_occ_user_oidc_provider_identifier` to a unique identifier. +Populate your provider information in the `oidc_user_config_(settings_)` +like this: + +```yaml +oidc_user_config_identifier: my_provider +oidc_user_config_discovery_endpoint: https://idp.example.com/ +oidc_user_config_client_id: my-client-id +oidc_user_config_client_secret: my-client-secret + +# All options to the occ command are avaible in the +# `oidc_user_config_settings_` namespace +oidc_user_config_settings_unique_id: true +oidc_user_config_settings_send_id_token_hint: true +oidc_user_config_settings_mapping_display_name: name +oidc_user_config_settings_mapping_uid: preferred_username +oidc_user_config_settings_mapping_email: email +``` diff --git a/roles/oidc_user_backend/defaults/main.yml b/roles/oidc_user_backend/defaults/main.yml new file mode 100644 index 0000000..e2ffc39 --- /dev/null +++ b/roles/oidc_user_backend/defaults/main.yml @@ -0,0 +1,47 @@ +--- +oidc_user_deployment_method: host +oidc_user_deployment_become_user: ~ +oidc_user_deployment_method_docker_container_name: nextcloud +oidc_user_deployment_method_podman_container_name: nextcloud +oidc_user_occ_command: "php occ" +oidc_user_occ_user_oidc_provider_identifier: ~ + +oidc_user_config_identifier: ~ +oidc_user_config_client_id: ~ +oidc_user_config_client_secret: ~ +oidc_user_config_discovery_endpoint: ~ +oidc_user_config_end_session_endpoint: ~ +oidc_user_config_scopes: + - openid + - email + - profile + +oidc_user_config_settings_unique_id: true +oidc_user_config_settings_check_bearer: true +oidc_user_config_settings_send_id_token_hint: true +oidc_user_config_settings_bearer_provisioning: false +oidc_user_config_settings_extra_claims: [] +oidc_user_config_settings_provider_based_id: false +oidc_user_config_settings_group_provisioning: false + +oidc_user_config_settings_mapping_display_name: name +oidc_user_config_settings_mapping_email: email +oidc_user_config_settings_mapping_quota: ~ +oidc_user_config_settings_mapping_uid: sub +oidc_user_config_settings_mapping_groups: ~ +oidc_user_config_settings_mapping_address: ~ +oidc_user_config_settings_mapping_street_address: ~ +oidc_user_config_settings_mapping_postal_code: ~ +oidc_user_config_settings_mapping_locality: ~ +oidc_user_config_settings_mapping_region: ~ +oidc_user_config_settings_mapping_country: ~ +oidc_user_config_settings_mapping_website: ~ +oidc_user_config_settings_mapping_avatar: ~ +oidc_user_config_settings_mapping_twitter: ~ +oidc_user_config_settings_mapping_fediverse: ~ +oidc_user_config_settings_mapping_organisation: ~ +oidc_user_config_settings_mapping_role: ~ +oidc_user_config_settings_mapping_headline: ~ +oidc_user_config_settings_mapping_biography: ~ +oidc_user_config_settings_mapping_phone: ~ +oidc_user_config_settings_mapping_gender: ~ diff --git a/roles/oidc_user_backend/tasks/main.yml b/roles/oidc_user_backend/tasks/main.yml new file mode 100644 index 0000000..9df8829 --- /dev/null +++ b/roles/oidc_user_backend/tasks/main.yml @@ -0,0 +1,29 @@ +--- + +- name: Check if deployment method is supported + ansible.builtin.fail: + msg: >-2 + Deployment method '{{ oidc_user_deployment_method }}' is not supported! + Supported are: {{ oidc_user_deployment_methods | join(', ') }} + when: oidc_user_deployment_method not in oidc_user_deployment_methods + +- name: Configure OIDC provider + ansible.builtin.command: + cmd: "{{ oidc_user_occ_user_oidc_provider_set_command }}" + become_user: "{{ oidc_user_deployment_become_user }}" + become: "{{ oidc_user_deployment_become_user | default(false, true) }}" + when: oidc_user_deployment_method == 'host' + +- name: Configure OIDC provider (docker) + community.docker.docker_container_exec: + container: "{{ oidc_user_deployment_method_docker_container_name }}" + command: "{{ oidc_user_occ_user_oidc_provider_set_command }}" + user: "{{ oidc_user_deployment_become_user | default(omit, true) }}" + when: oidc_user_deployment_method == 'docker' + +- name: Configure OIDC provider (podman) + containers.podman.podman_container_exec: + name: "{{ oidc_user_deployment_method_podman_container_name }}" + command: "{{ oidc_user_occ_user_oidc_provider_set_command }}" + user: "{{ oidc_user_deployment_become_user | default(omit, true) }}" + when: oidc_user_deployment_method == 'podman' diff --git a/roles/oidc_user_backend/vars/main.yml b/roles/oidc_user_backend/vars/main.yml new file mode 100644 index 0000000..d26f88e --- /dev/null +++ b/roles/oidc_user_backend/vars/main.yml @@ -0,0 +1,63 @@ +--- +oidc_user_deployment_methods: + - host + - docker + - podman + +oidc_user_occ_user_oidc_options_dict: + clientid: "{{ oidc_user_config_client_id }}" + clientsecret: "{{ oidc_user_config_client_secret }}" + discoveryuri: "{{ oidc_user_config_discovery_endpoint }}" + endsessionendpointuri: "{{ oidc_user_config_end_session_endpoint }}" + scope: "'{{ oidc_user_config_scopes | default([], true) | join(' ') }}'" + "unique-uid": >-2 + {{ oidc_user_config_settings_unique_id | bool | ternary(1, 0) }} + "check-bearer": >-2 + {{ oidc_user_config_settings_check_bearer | bool | ternary(1, 0) }} + "send-id-token-hint": >-2 + {{ oidc_user_config_settings_send_id_token_hint | bool | ternary(1, 0) }} + "group-provisioning": >-2 + {{ oidc_user_config_settings_group_provisioning | bool | ternary(1, 0) }} + "extra-claims": >-2 + {{ (oidc_user_config_settings_extra_claims | default([]) | length > 0) + | ternary(oidc_user_config_settings_extra_claims | join(' ') | quote, '') }} + +oidc_user_occ_user_oidc_mapping_options_dict: + "display-name": "{{ oidc_user_config_settings_mapping_display_name }}" + email: "{{ oidc_user_config_settings_mapping_email }}" + quota: "{{ oidc_user_config_settings_mapping_quota }}" + uid: "{{ oidc_user_config_settings_mapping_uid }}" + groups: "{{ oidc_user_config_settings_mapping_groups }}" + website: "{{ oidc_user_config_settings_mapping_website }}" + avatar: "{{ oidc_user_config_settings_mapping_avatar }}" + twitter: "{{ oidc_user_config_settings_mapping_twitter }}" + fediverse: "{{ oidc_user_config_settings_mapping_fediverse }}" + organisation: "{{ oidc_user_config_settings_mapping_organisation }}" + role: "{{ oidc_user_config_settings_mapping_role }}" + headline: "{{ oidc_user_config_settings_mapping_headline }}" + biography: "{{ oidc_user_config_settings_mapping_biography }}" + phone: "{{ oidc_user_config_settings_mapping_phone }}" + gender: "{{ oidc_user_config_settings_mapping_gender }}" + address: "{{ oidc_user_config_settings_mapping_address }}" + street_address: "{{ oidc_user_config_settings_mapping_street_address }}" + postal_code: "{{ oidc_user_config_settings_mapping_postal_code }}" + locality: "{{ oidc_user_config_settings_mapping_locality }}" + region: "{{ oidc_user_config_settings_mapping_region }}" + country: "{{ oidc_user_config_settings_mapping_country }}" + +oidc_user_occ_user_oidc_provider_options: >-2 + {% for tuple in oidc_user_occ_user_oidc_options_dict | dict2items %} + {% if tuple.value | default(false, true) %} + --{{ tuple.key }}={{ tuple.value }} + {% endif %} + {% endfor %} + {% for tuple in oidc_user_occ_user_oidc_mapping_options_dict | dict2items %} + {% if tuple.value | default(false, true) %} + --mapping-{{ tuple.key }}={{ tuple.value }} + {% endif %} + {% endfor %} + +oidc_user_occ_user_oidc_provider_set_command: >-2 + {{ oidc_user_occ_command }} user_oidc:provider + {{ oidc_user_occ_user_oidc_provider_options }} + {{ oidc_user_occ_user_oidc_provider_identifier }}