diff --git a/roles/docker-nextcloud/Administration.md b/roles/docker-nextcloud/Administration.md new file mode 100644 index 00000000..2cb11a97 --- /dev/null +++ b/roles/docker-nextcloud/Administration.md @@ -0,0 +1,5 @@ +# Administration + +## Logs + +The logs you will find here on the host: **/var/lib/docker/volumes/nextcloud_data/_data/data/nextcloud.log** \ No newline at end of file diff --git a/roles/docker-oauth2-proxy/vars/configuration.yml b/roles/docker-oauth2-proxy/vars/configuration.yml index 7e5ad8bc..dceeaf7c 100644 --- a/roles/docker-oauth2-proxy/vars/configuration.yml +++ b/roles/docker-oauth2-proxy/vars/configuration.yml @@ -1,6 +1,6 @@ configuration_file: "oauth2-proxy-keycloak.cfg" # Needs to be set true in the roles which use it version: "latest" # Docker Image version -allowed_roles: admin # Restrict it default to admin role. Use the vars/main.yml to open the specific role for other groups +allowed_roles: "admin" # Restrict it default to admin role. Use the vars/main.yml to open the specific role for other groups features: matomo: true css: true diff --git a/roles/docker-openproject/vars/configuration.yml b/roles/docker-openproject/vars/configuration.yml index 9f980072..de6afc84 100644 --- a/roles/docker-openproject/vars/configuration.yml +++ b/roles/docker-openproject/vars/configuration.yml @@ -2,6 +2,11 @@ version: "13" # Update when available. Sadly no rolling release oauth2_proxy: application: "proxy" port: "80" + acl: + whitelist: + - "/users/me" # Necessary for Nextcloud Plugin to work + - "/api/" # Necessary for Nextcloud Plugin to work + - "/oauth/token" # Necessary for Nextcloud Plugin to work ldap: filters: administrators: True # Set true to filter administrators diff --git a/roles/docker-yourls/vars/configuration.yml b/roles/docker-yourls/vars/configuration.yml index ed394205..5a398bda 100644 --- a/roles/docker-yourls/vars/configuration.yml +++ b/roles/docker-yourls/vars/configuration.yml @@ -5,7 +5,9 @@ version: "latest" oauth2_proxy: application: "application" port: "80" - location: "/admin/" # Protects the admin area + acl: + blacklist: + - "/admin/" # Protects the admin area features: matomo: true css: true diff --git a/roles/nginx-docker-reverse-proxy/templates/vhost/basic.conf.j2 b/roles/nginx-docker-reverse-proxy/templates/vhost/basic.conf.j2 index 7309cc02..d632869e 100644 --- a/roles/nginx-docker-reverse-proxy/templates/vhost/basic.conf.j2 +++ b/roles/nginx-docker-reverse-proxy/templates/vhost/basic.conf.j2 @@ -15,21 +15,47 @@ server {% include 'roles/letsencrypt/templates/ssl_header.j2' %} - {% if applications | is_feature_enabled('oauth2',application_id) %} - {% if applications[application_id].oauth2_proxy.location is defined %} - {# Exposed and Unprotected Location #} + {% if applications | is_feature_enabled('oauth2', application_id) %} + {% set acl = applications[application_id].oauth2_proxy.acl | default({}) %} + + {% if acl.blacklist is defined %} + {# 1. Expose everything by default, then protect blacklisted paths #} + {% set oauth2_proxy_enabled = false %} + {% set location = "/" %} {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %} + + {% for loc in acl.blacklist %} + {% set oauth2_proxy_enabled = true %} + {% set location = loc %} + {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %} + {% endfor %} + + {% elif acl.whitelist is defined %} + {# 2. Protect everything by default, then expose whitelisted paths #} {% set oauth2_proxy_enabled = true %} - {% set location = applications[application_id].oauth2_proxy.location %} - {# Gated Location by OAuth2 Proxy #} + {% set location = "/" %} {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %} + + {% for loc in acl.whitelist %} + {% set oauth2_proxy_enabled = false %} + {% set location = loc %} + {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %} + {% endfor %} + {% else %} + {# 3. OAuth2 enabled but no (or empty) ACL — protect all #} {% set oauth2_proxy_enabled = true %} - {# Protected Domain by OAuth2 Proxy #} - {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2'%} + {% set location = "/" %} + {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %} {% endif %} + {% else %} - {# Exposed Domain - Not protected by OAuth2 Proxy #} + {# 4. OAuth2 completely disabled — expose all #} + {% set oauth2_proxy_enabled = false %} + {% set location = "/" %} {% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %} {% endif %} + } + + diff --git a/tests/integration/test_oauth2_acl_mutual_exclusive.py b/tests/integration/test_oauth2_acl_mutual_exclusive.py new file mode 100644 index 00000000..a62196ad --- /dev/null +++ b/tests/integration/test_oauth2_acl_mutual_exclusive.py @@ -0,0 +1,45 @@ +import os +import yaml +import unittest +from pathlib import Path + +ROLES_DIR = Path(__file__).resolve().parent.parent.parent / "roles" + +class TestOauth2AclMutualExclusion(unittest.TestCase): + def test_acl_has_either_whitelist_or_blacklist(self): + failures = [] + + for role_path in ROLES_DIR.iterdir(): + vars_file = role_path / "vars" / "configuration.yml" + if not vars_file.exists(): + continue + + # open the YAML file instead of passing the Path object + try: + with open(vars_file) as f: + data = yaml.safe_load(f) or {} + except yaml.YAMLError as e: + failures.append(f"{role_path.name}: failed to parse YAML ({e})") + continue + + oauth2 = data.get("oauth2_proxy", {}) + acl = oauth2.get("acl", None) + if acl is None: + continue + + has_wl = "whitelist" in acl + has_bl = "blacklist" in acl + + if has_wl and has_bl: + failures.append( + f"{role_path.name}: both 'whitelist' and 'blacklist' are defined" + ) + + if failures: + self.fail( + "The following roles define both whitelist and blacklist under oauth2_proxy.acl:\n" + + "\n".join(failures) + ) + +if __name__ == "__main__": + unittest.main()