diff --git a/roles/docker-ldap/tasks/lam.yml b/roles/docker-ldap/tasks/lam.yml index b68e17a6..09ba8c3c 100644 --- a/roles/docker-ldap/tasks/lam.yml +++ b/roles/docker-ldap/tasks/lam.yml @@ -9,25 +9,25 @@ mode: '0755' recurse: true -- name: "create {{docker_compose.directories.env}}lam.env" - template: - src: "lam/env.j2" - dest: "{{docker_compose.directories.env}}lam.env" - mode: '770' - force: yes - notify: docker compose project setup - -- name: "create default.group to enable groupOfNames in LAM" - template: - src: "lam/default.group.j2" - dest: "{{ lam_profiles_dir }}/default.group" - mode: '0644' - notify: docker compose project setup - -- name: "Create groupOfNames.conf to enable groupOfNames as base module in LAM" - template: - src: "lam/groupOfNames.conf.j2" - dest: "{{ lam_profiles_dir }}/groupOfNames.conf" - mode: '0644' +#- name: "create {{docker_compose.directories.env}}lam.env" +# template: +# src: "lam/env.j2" +# dest: "{{docker_compose.directories.env}}lam.env" +# mode: '770' +# force: yes +# notify: docker compose project setup +# +#- name: "create default.group to enable groupOfNames in LAM" +# template: +# src: "lam/default.group.j2" +# dest: "{{ lam_profiles_dir }}/default.group" +# mode: '0644' +# notify: docker compose project setup +# +#- name: "Create groupOfNames.conf to enable groupOfNames as base module in LAM" +# template: +# src: "lam/groupOfNames.conf.j2" +# dest: "{{ lam_profiles_dir }}/groupOfNames.conf" +# mode: '0644' diff --git a/roles/docker-ldap/templates/docker-compose.yml.j2 b/roles/docker-ldap/templates/docker-compose.yml.j2 index 86f8b6f1..eaa0f05f 100644 --- a/roles/docker-ldap/templates/docker-compose.yml.j2 +++ b/roles/docker-ldap/templates/docker-compose.yml.j2 @@ -13,8 +13,8 @@ services: - 127.0.0.1:{{ports.localhost.http.ldap}}:80 env_file: - "{{docker_compose.directories.env}}lam.env" - volumes: - - "{{ lam_profiles_dir }}:/var/lib/ldap-account-manager/config/profiles/" +# volumes: +# - "{{ lam_profiles_dir }}:/var/lib/ldap-account-manager/config/profiles/" {% elif applications.ldap.webinterface == 'phpldapadmin' %} image: leenooks/phpldapadmin:{{applications.ldap.phpldapadmin.version}} diff --git a/roles/docker-openproject/vars/ldap.yml b/roles/docker-openproject/vars/ldap.yml index 1d61d5f5..6f2b0a10 100644 --- a/roles/docker-openproject/vars/ldap.yml +++ b/roles/docker-openproject/vars/ldap.yml @@ -1,17 +1,17 @@ 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 }}" # Bind DN (used for authentication) - account_password: "{{ ldap.bind_credential }}" # Bind password - base_dn: "{{ ldap.dn.users }}" # Base DN for user search - attr_login: "{{ ldap.attributes.user_id | default('uid') }}" # LDAP attribute used for login - attr_firstname: "givenName" # LDAP attribute for first name - attr_lastname: "sn" # LDAP attribute for last name - attr_mail: "mail" # LDAP attribute for email - attr_admin: "" # 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 - verify_peer: false # Whether to verify the SSL certificate - filter_string: "" # Optional: Custom filter for users (e.g., "(objectClass=person)") - tls_certificate_string: "" # Optional: Client certificate string for TLS (usually left empty) \ No newline at end of file + 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 }}" # Bind DN (used for authentication) + account_password: "{{ ldap.bind_credential }}" # Bind password + base_dn: "{{ ldap.dn.users }}" # Base DN for user search + attr_login: "{{ ldap.attributes.user_id }}" # LDAP attribute used for login + attr_firstname: "givenName" # LDAP attribute for first name + attr_lastname: "sn" # LDAP attribute for last name + attr_mail: "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 + verify_peer: false # Whether to verify the SSL certificate + filter_string: "{{ openproject_filters.users }}" # Optional: Custom filter for users (e.g., "(objectClass=person)") + tls_certificate_string: "" # Optional: Client certificate string for TLS (usually left empty) \ No newline at end of file diff --git a/roles/docker-openproject/vars/main.yml b/roles/docker-openproject/vars/main.yml index 985d1884..defa5c16 100644 --- a/roles/docker-openproject/vars/main.yml +++ b/roles/docker-openproject/vars/main.yml @@ -1,6 +1,6 @@ application_id: "openproject" docker_repository_address: "https://github.com/opf/openproject-deploy" -database_password: "{{applications[application_id].credentials.database_password}}" +database_password: "{{ applications[application_id].credentials.database_password }}" database_type: "postgres" openproject_plugins_service: "{{docker_compose.directories.services}}plugins/" @@ -10,9 +10,18 @@ custom_openproject_image: "custom_openproject" dummy_volume: "{{docker_compose.directories.volumes}}dummy_volume" openproject_rails_settings: - email_delivery_method: "smtp" - smtp_address: "{{ system_email.host }}" - smtp_domain: "{{ system_email.domain }}" - smtp_user_name: "{{ system_email.username }}" - smtp_password: "{{ system_email.password }}" - smtp_ssl: false \ No newline at end of file + email_delivery_method: "smtp" + smtp_address: "{{ system_email.host }}" + smtp_domain: "{{ system_email.domain }}" + smtp_user_name: "{{ system_email.username }}" + smtp_password: "{{ system_email.password }}" + smtp_ssl: false + +openproject_filters: + administrators: >- + {{ '(memberOf=cn=openproject-admins,' ~ ldap.dn.application_roles ~ ')' + if applications[application_id].ldap.filters.administrators else '' }} + + users: >- + {{ '(memberOf=cn=openproject-users,' ~ ldap.dn.application_roles ~ ')' + if applications[application_id].ldap.filters.users else '' }} \ No newline at end of file diff --git a/roles/docker-taiga/Development.md b/roles/docker-taiga/Development.md index 2539d9d5..a996e33a 100644 --- a/roles/docker-taiga/Development.md +++ b/roles/docker-taiga/Development.md @@ -1,4 +1,4 @@ -# Development +# Development Notes ## Build front container @@ -12,4 +12,26 @@ Verify front configuration: ```bash docker compose exec -it taiga-front cat /usr/share/nginx/html/conf.json +``` + +Verify the backend configuration: +```bash +docker compose exec -it taiga-back cat /taiga-back/settings/local.py +``` + +## Additional Configuration for plugin +```bash +# ENABLE_OPENID Plugin +ENABLE_OPENID = os.getenv('ENABLE_OPENID', 'False') == 'True' +if ENABLE_OPENID: + INSTALLED_APPS += [ + "taiga_contrib_openid_auth" + ] + OPENID_USER_URL = os.getenv('OPENID_USER_URL') + OPENID_TOKEN_URL = os.getenv('OPENID_TOKEN_URL') + OPENID_CLIENT_ID = os.getenv('OPENID_CLIENT_ID') + OPENID_CLIENT_SECRET = os.getenv('OPENID_CLIENT_SECRET') + OPENID_SCOPE = os.getenv('OPENID_SCOPE') + OPENID_FILTER = os.getenv('OPENID_FILTER') + OPENID_FILTER_FIELD = os.getenv('OPENID_FILTER_FIELD') ``` \ No newline at end of file diff --git a/roles/docker-taiga/README.md b/roles/docker-taiga/README.md index 7a736644..8e882837 100644 --- a/roles/docker-taiga/README.md +++ b/roles/docker-taiga/README.md @@ -34,7 +34,9 @@ By using this role, teams can set up Taiga in minutes on Arch Linux systems β€” ## Features - 🐳 **Docker-Based Deployment:** Easy containerized setup of backend, frontend, async workers, and events service. -- πŸ” **OIDC (Single Sign-On):** Supported via [taiga-contrib-openid-auth (robrotheram)](https://github.com/robrotheram/taiga-contrib-openid-auth) +- πŸ” **OIDC (Single Sign-On):** Supported via: + - [taiga-contrib-openid-auth (robrotheram)](https://github.com/robrotheram/taiga-contrib-openid-auth) + - [taiga-contrib-oidc-auth (official)](https://github.com/taigaio/taiga-contrib-oidc-auth) - πŸ“¨ **Email Backend:** Supports SMTP and console backends for development. - πŸ” **Async & Realtime Events:** Includes RabbitMQ and support for Taiga’s event system. - 🌐 **Reverse Proxy Ready:** Integrates with Nginx using the `nginx-domain-setup` role. diff --git a/roles/docker-taiga/tasks/main.yml b/roles/docker-taiga/tasks/main.yml index 47b6ebbf..ebdfa95a 100644 --- a/roles/docker-taiga/tasks/main.yml +++ b/roles/docker-taiga/tasks/main.yml @@ -14,6 +14,12 @@ include_role: name: docker-repository-setup +- name: "template local.py for taiga-contrib-oidc-auth" + template: + src: taiga/local.py.j2 + dest: "{{ docker_compose.directories.config }}taiga-local.py" + when: applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'taigaio' + - name: "create {{docker_compose_init}}" template: src: "docker-compose-inits.yml.j2" diff --git a/roles/docker-taiga/templates/docker-compose.yml.j2 b/roles/docker-taiga/templates/docker-compose.yml.j2 index 6daf1a32..3d93a944 100644 --- a/roles/docker-taiga/templates/docker-compose.yml.j2 +++ b/roles/docker-taiga/templates/docker-compose.yml.j2 @@ -8,6 +8,13 @@ services: - static-data:/taiga-back/static - media-data:/taiga-back/media # - ./config.py:/taiga-back/settings/config.py + +{% if applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'taigaio' %} + + - {{ docker_compose.directories.config }}taiga-local.py:/taiga-back/settings/local.py:ro + +{% endif %} + {% include 'templates/docker/container/networks.yml.j2' %} taiga: {% include 'templates/docker/container/depends-on-also-database.yml.j2' %} @@ -15,6 +22,15 @@ services: condition: service_started taiga-async-rabbitmq: condition: service_started +{% if applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'taigaio' %} + + command: > + /bin/sh -c " + pip install taiga-contrib-oidc-auth && + /taiga-back/docker/entrypoint.sh" + +{% endif %} + taiga-async: {% include 'roles/docker-compose/templates/services/base.yml.j2' %} @@ -25,6 +41,13 @@ services: - static-data:/taiga-back/static - media-data:/taiga-back/media # - ./config.py:/taiga-back/settings/config.py + +{% if applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'taigaio' %} + + - {{ docker_compose.directories.config }}taiga-local.py:/taiga-back/settings/local.py:ro + +{% endif %} + {% include 'templates/docker/container/networks.yml.j2' %} taiga: {% include 'templates/docker/container/depends-on-also-database.yml.j2' %} @@ -32,6 +55,14 @@ services: condition: service_started taiga-async-rabbitmq: condition: service_started +{% if applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'taigaio' %} + + command: > + /bin/sh -c " + pip install taiga-contrib-oidc-auth && + /taiga-back/docker/entrypoint.sh" + +{% endif %} taiga-async-rabbitmq: image: rabbitmq:3.8-management-alpine diff --git a/roles/docker-taiga/templates/env.j2 b/roles/docker-taiga/templates/env.j2 index 3c8f10a8..b54f3c52 100644 --- a/roles/docker-taiga/templates/env.j2 +++ b/roles/docker-taiga/templates/env.j2 @@ -26,7 +26,7 @@ EMAIL_BACKEND: = "django.core.mail.backends.{{email_backend}}.EmailBacken DEFAULT_FROM_EMAIL = "{{system_email.from}}" # EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive (only set one of those to True) -EMAIL_USE_TLS = "{{ system_email.tls | lower | capitalize }}" # use TLS (secure) connection with the SMTP server +EMAIL_USE_TLS = "{{ system_email.tls | capitalize }}" # use TLS (secure) connection with the SMTP server EMAIL_USE_SSL = "{{ 'False' if system_email.start_tls else 'True' }}" # use implicit TLS (secure) connection with the SMTP server RABBITMQ_USER=taiga @@ -48,8 +48,30 @@ MAX_AGE = 360 ENABLE_TELEMETRY = True {% if applications[application_id].oidc.enabled %} -# OICD -# @See https://github.com/robrotheram/taiga-contrib-openid-auth + +{% if applications[application_id].oidc.flavor == 'taigaio' %} + +# OIDC via taigaio official contrib +# @See https://github.com/taigaio/taiga-contrib-oidc-auth +ENABLE_OIDC=True +OIDC_RP_CLIENT_ID="{{ oidc.client.id }}" +OIDC_RP_CLIENT_SECRET="{{ oidc.client.secret }}" +OIDC_OP_AUTHORIZATION_ENDPOINT="{{ oidc.client.authorize_url }}" +OIDC_OP_TOKEN_ENDPOINT="{{ oidc.client.token_url }}" +OIDC_OP_USER_ENDPOINT="{{ oidc.client.user_info_url }}" +OIDC_RP_SIGN_ALGO="RS256" +OIDC_RP_SCOPES="openid profile email" +OIDC_USE_STATE=True +OIDC_USE_NONCE=True +OIDC_RP_CALLBACK_URL="{{ oidc.client.redirect_uri | default('') }}" +OIDC_OP_JWKS_ENDPOINT="{{ oidc.client.jwks_url | default('') }}" + +{% endif %} + +{% if applications[application_id].oidc.flavor == 'robrotheram' %} + +# OIDC via robrotheram +# @see https://github.com/robrotheram/taiga-contrib-openid-auth ENABLE_OPENID=True OPENID_URL="{{oidc.client.authorize_url}}" OPENID_USER_URL="{{oidc.client.user_info_url}}" @@ -58,14 +80,14 @@ OPENID_CLIENT_ID="{{oidc.client.id}}" OPENID_CLIENT_SECRET="{{oidc.client.secret}}" OPENID_NAME="{{oidc.button_text}}" OPENID_USERNAME_FIELD="{{oidc.attributes.username}}" - -# Default Values +# Optional: # OPENID_ID_FIELD="sub" # OPENID_FULLNAME_FIELD="name" # OPENID_EMAIL_FIELD="email" # OPENID_SCOPE="openid email" +# OPENID_FILTER = "taiga_users,taiga_admins" +# OPENID_FILTER_FIELD = "groups" + +{% endif %} -# The following are optional fields to configure filtering users based on the openid-userinfo. A common use case is to allow only specific roles or groups to log into taiga. OPENID_FILTER_FIELD is the name of the claim that's present in the UserInfo. The field is expected to be a list of strings. OPENID_FILTER is the allowed values, comma seperated. -#OPENID_FILTER = "taiga_users,taiga_admins" -#OPENID_FILTER_FIELD = "groups" {% endif %} \ No newline at end of file diff --git a/roles/docker-taiga/templates/local.py.j2 b/roles/docker-taiga/templates/local.py.j2 new file mode 100644 index 00000000..e71acc53 --- /dev/null +++ b/roles/docker-taiga/templates/local.py.j2 @@ -0,0 +1,24 @@ +INSTALLED_APPS += [ + "mozilla_django_oidc", + "taiga_contrib_oidc_auth", +] + +AUTHENTICATION_BACKENDS = list(AUTHENTICATION_BACKENDS) + [ + "taiga_contrib_oidc_auth.oidc.TaigaOIDCAuthenticationBackend", +] + +ROOT_URLCONF = "settings.urls" + +OIDC_CALLBACK_CLASS = "taiga_contrib_oidc_auth.views.TaigaOIDCAuthenticationCallbackView" +OIDC_RP_SCOPES = "openid profile email" +OIDC_RP_SIGN_ALGO = "RS256" + +OIDC_BASE_URL = "{{ oidc.base_url }}" +OIDC_OP_JWKS_ENDPOINT = OIDC_BASE_URL + "/Jwks" +OIDC_OP_AUTHORIZATION_ENDPOINT = OIDC_BASE_URL + "/Authorization" +OIDC_OP_TOKEN_ENDPOINT = OIDC_BASE_URL + "/Token" +OIDC_OP_USER_ENDPOINT = OIDC_BASE_URL + "/UserInfo" + +import os +OIDC_RP_CLIENT_ID = os.getenv("OIDC_RP_CLIENT_ID") +OIDC_RP_CLIENT_SECRET = os.getenv("OIDC_RP_CLIENT_SECRET") diff --git a/roles/docker-taiga/vars/main.yml b/roles/docker-taiga/vars/main.yml index 16e9f5cb..5de6487c 100644 --- a/roles/docker-taiga/vars/main.yml +++ b/roles/docker-taiga/vars/main.yml @@ -4,6 +4,10 @@ database_password: "{{taiga_database_password}}" docker_repository_address: "https://github.com/taigaio/taiga-docker" email_backend: "smtp" ## use an SMTP server or display the emails in the console (either "smtp" or "console") docker_compose_init: "{{docker_compose.directories.instance}}docker-compose-inits.yml.j2" -taiga_image_backend: "{{ 'robrotheram/taiga-back-openid' if applications[application_id].oidc.enabled else 'taigaio/taiga-back' }}" -taiga_image_frontend: "{{ 'robrotheram/taiga-front-openid' if applications[application_id].oidc.enabled else 'taigaio/taiga-front' }}" +taiga_image_backend: >- + {{ 'robrotheram/taiga-back-openid' if applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'robrotheram' + else 'taigaio/taiga-back' }} +taiga_image_frontend: >- + {{ 'robrotheram/taiga-front-openid' if applications[application_id].oidc.enabled and applications[application_id].oidc.flavor == 'robrotheram' + else 'taigaio/taiga-front' }} taiga_frontend_conf_path: "{{docker_compose.directories.config}}conf.json"