Solved oauth2 proxy configuration bugs

This commit is contained in:
Kevin Veen-Birkenbach 2025-05-13 09:16:34 +02:00
parent 9ea92ea9ec
commit 7ce480bd5c
No known key found for this signature in database
GPG Key ID: 44D8F11FD62F878E
7 changed files with 112 additions and 15 deletions

View File

@ -1,4 +1,4 @@
- name: "set _tmp_database_application_id (Needed due to lazzy loading issue)" - name: "set database_application_id (Needed due to lazzy loading issue)"
set_fact: set_fact:
database_application_id: "{{ application_id }}" database_application_id: "{{ application_id }}"

View File

@ -1,6 +1,6 @@
- name: "Transfering oauth2-proxy-keycloak.cfg.j2 to {{docker_compose.directories.volumes}}" - name: "Transfering oauth2-proxy-keycloak.cfg.j2 to {{docker_compose.directories.volumes}}"
template: template:
src: oauth2-proxy-keycloak.cfg.j2 src: oauth2-proxy-keycloak.cfg.j2
dest: "{{docker_compose.directories.volumes}}{{applications.oauth2_proxy.configuration_file}}" dest: "{{docker_compose.directories.volumes}}{{applications[application_id].configuration_file}}"
notify: notify:
- docker compose project setup - docker compose project setup

View File

@ -1,8 +1,8 @@
http_address = "0.0.0.0:4180" http_address = "0.0.0.0:4180"
cookie_secret = "{{ applications[application_id].credentials.oauth2_proxy_cookie_secret }}" cookie_secret = "{{ applications[oauth2_proxy_application_id].credentials.oauth2_proxy_cookie_secret }}"
email_domains = "{{ primary_domain }}" email_domains = "{{ primary_domain }}"
cookie_secure = "true" # True is necessary to force the cookie set via https cookie_secure = "true" # True is necessary to force the cookie set via https
upstreams = "http://{{applications[application_id].oauth2_proxy.application}}:{{applications[application_id].oauth2_proxy.port}}" upstreams = "http://{{ applications[oauth2_proxy_application_id].oauth2_proxy.application }}:{{ applications[oauth2_proxy_application_id].oauth2_proxy.port }}"
cookie_domains = ["{{ domain }}", "{{ domains.keycloak }}"] # Required so cookie can be read on all subdomains. cookie_domains = ["{{ domain }}", "{{ domains.keycloak }}"] # Required so cookie can be read on all subdomains.
whitelist_domains = [".{{ primary_domain }}"] # Required to allow redirection back to original requested target. whitelist_domains = [".{{ primary_domain }}"] # Required to allow redirection back to original requested target.
@ -16,5 +16,5 @@ provider_display_name = "Keycloak"
# role restrictions # role restrictions
#cookie_roles = "realm_access.roles" #cookie_roles = "realm_access.roles"
#allowed_groups = "{{applications.oauth2_proxy.allowed_roles}}" # This is not correct here. needs to be placed in applications @todo move there when implementing #allowed_groups = "{{ applications[oauth2_proxy_application_id].allowed_roles }}" # This is not correct here. needs to be placed in applications @todo move there when implementing
# @see https://chatgpt.com/share/67f42607-bf68-800f-b587-bd56fe9067b5 # @see https://chatgpt.com/share/67f42607-bf68-800f-b587-bd56fe9067b5

View File

@ -0,0 +1 @@
application_id: oauth2-proxy

View File

@ -8,7 +8,12 @@
dest: "{{ configuration_destination }}" dest: "{{ configuration_destination }}"
notify: restart nginx notify: restart nginx
- name: "set oauth2_proxy_application_id (Needed due to lazzy loading issue)"
set_fact:
oauth2_proxy_application_id: "{{ application_id }}"
when: "{{applications[application_id].get('features', {}).get('oauth2', False)}}"
- name: "include the docker-oauth2-proxy role {{domain}}" - name: "include the docker-oauth2-proxy role {{domain}}"
include_role: include_role:
name: docker-oauth2-proxy name: docker-oauth2-proxy
when: final_oauth2_enabled | bool when: "{{applications[application_id].get('features', {}).get('oauth2', False)}}"

View File

@ -1,2 +1 @@
configuration_destination: "{{nginx.directories.http.servers}}{{domain}}.conf" configuration_destination: "{{nginx.directories.http.servers}}{{domain}}.conf"
final_oauth2_enabled: "{{applications[application_id].get('features', {}).get('oauth2', False)}}"

View File

@ -0,0 +1,92 @@
# tests/unit/test_configuration_filters.py
import unittest
from filter_plugins.configuration_filters import (
is_feature_enabled,
get_csp_whitelist,
get_csp_flags,
)
class TestConfigurationFilters(unittest.TestCase):
def setUp(self):
# Sample applications data for testing
self.applications = {
'app1': {
'features': {
'oauth2': True,
},
'csp': {
'whitelist': {
# directive with a list
'script-src': ['https://example.com'],
# directive with a single string
'connect-src': 'https://api.example.com',
},
'flags': {
# both flags for script-src
'script-src': {
'unsafe_eval': True,
'unsafe_inline': False,
},
# only unsafe_inline for style-src
'style-src': {
'unsafe_inline': True,
},
},
},
},
'app2': {
# no features or csp defined
},
}
# Tests for is_feature_enabled
def test_is_feature_enabled_true(self):
self.assertTrue(is_feature_enabled(self.applications, 'oauth2', 'app1'))
def test_is_feature_enabled_false_missing_feature(self):
self.assertFalse(is_feature_enabled(self.applications, 'nonexistent', 'app1'))
def test_is_feature_enabled_false_missing_app(self):
self.assertFalse(is_feature_enabled(self.applications, 'oauth2', 'unknown_app'))
# Tests for get_csp_whitelist
def test_get_csp_whitelist_returns_list_as_is(self):
result = get_csp_whitelist(self.applications, 'app1', 'script-src')
self.assertEqual(result, ['https://example.com'])
def test_get_csp_whitelist_wraps_string_in_list(self):
result = get_csp_whitelist(self.applications, 'app1', 'connect-src')
self.assertEqual(result, ['https://api.example.com'])
def test_get_csp_whitelist_empty_when_not_defined(self):
result = get_csp_whitelist(self.applications, 'app1', 'frame-src')
self.assertEqual(result, [])
def test_get_csp_whitelist_empty_when_app_missing(self):
result = get_csp_whitelist(self.applications, 'nonexistent_app', 'script-src')
self.assertEqual(result, [])
# Tests for get_csp_flags
def test_get_csp_flags_includes_unsafe_eval(self):
result = get_csp_flags(self.applications, 'app1', 'script-src')
self.assertIn("'unsafe-eval'", result)
self.assertNotIn("'unsafe-inline'", result)
def test_get_csp_flags_includes_unsafe_inline(self):
result = get_csp_flags(self.applications, 'app1', 'style-src')
self.assertIn("'unsafe-inline'", result)
self.assertNotIn("'unsafe-eval'", result)
def test_get_csp_flags_empty_when_none_configured(self):
result = get_csp_flags(self.applications, 'app1', 'connect-src')
self.assertEqual(result, [])
def test_get_csp_flags_empty_when_app_missing(self):
result = get_csp_flags(self.applications, 'nonexistent_app', 'script-src')
self.assertEqual(result, [])
if __name__ == '__main__':
unittest.main()