diff --git a/charts/dawarich/README.md b/charts/dawarich/README.md index 5e4b6d8ac..818ee9c1a 100644 --- a/charts/dawarich/README.md +++ b/charts/dawarich/README.md @@ -122,10 +122,12 @@ initial public administrator. No HTTP server runs during model provisioning. An existing unsafe demo credential blocks startup and requires explicit repair. The public proxy forwards to a Rails listener bound exclusively to loopback. It -denies the unconditional native API registration routes, Apple/Google enrollment, -the OAuth web namespace and the public signup page. The chart implements a -local-account policy; enabling an OAuth environment variable does not remove these -guards. +denies the native API registration routes and Apple/Google enrollment. The public +signup page remains denied in every configuration. The OAuth web namespace +(`/users/auth`) is denied while `oidc.enabled` is false; with OIDC enabled the +proxy forwards `/users/auth` to Rails so provider sign-in can complete. The chart +implements a local-account policy: OIDC federation opens only that sign-in +round-trip and never public registration. A chart-owned initializer uses the Rails middleware extension point to reject Devise account creation after `Rack::MethodOverride` has interpreted HTML form diff --git a/charts/dawarich/docs/identity.md b/charts/dawarich/docs/identity.md index 8a2909fd3..ef77056f5 100644 --- a/charts/dawarich/docs/identity.md +++ b/charts/dawarich/docs/identity.md @@ -16,7 +16,10 @@ rotate their passwords. ## Registration policy Rails binds only to loopback on port 3010. The public NGINX listener denies native -API registration and Apple/Google enrollment, the signup page and web OAuth routes. +API registration and Apple/Google enrollment, and denies the signup page in every +configuration. The web OAuth namespace (`/users/auth`) is denied while +`oidc.enabled` is false; with OIDC enabled the proxy forwards `/users/auth` so +provider sign-in can complete. A documented Rails middleware initializer rejects Devise account creation after `Rack::MethodOverride`, so authenticated profile update and deletion retain their native HTTP methods. Native registration is also disabled in the cached setting. diff --git a/charts/dawarich/scripts/runtime-smoke.mjs b/charts/dawarich/scripts/runtime-smoke.mjs index e50e6e83f..e389538fd 100644 --- a/charts/dawarich/scripts/runtime-smoke.mjs +++ b/charts/dawarich/scripts/runtime-smoke.mjs @@ -42,7 +42,8 @@ try{ assert.deepEqual(listeners,['0100007F:0BC2'],'Native Rails listener must be exclusively IPv4 loopback'); await forward(async base=>{const request=client(base); assert.equal((await request('/api/v1/health')).status,200); - for(const path of ['/api/v1/auth/register','/api/v1/auth/register.json','/api/v1/auth/register/','/api/v1/auth/%72egister','/api/v1/auth%2fregister','//api/v1/auth/register','/api/v1/auth/apple','/api/v1/auth/google','/users','/users.json','/users/sign_up','/users/auth/openid_connect'])assert.equal((await request(path,{method:'POST',anonymous:true,json:{email:'never-created@example.test',password:'Owned-fixture-never-created'}})).status,403,'Public self-registration route must be denied: '+path); + for(const path of ['/api/v1/auth/register','/api/v1/auth/register.json','/api/v1/auth/register/','/api/v1/auth/%72egister','/api/v1/auth%2fregister','//api/v1/auth/register','/api/v1/auth/apple','/api/v1/auth/google','/users','/users.json','/users/sign_up'])assert.equal((await request(path,{method:'POST',anonymous:true,json:{email:'never-created@example.test',password:'Owned-fixture-never-created'}})).status,403,'Public self-registration route must be denied: '+path); + assert.equal((await request('/users/auth/openid_connect',{method:'POST',anonymous:true,json:{email:'never-created@example.test',password:'Owned-fixture-never-created'}})).status,values.oidc.enabled?422:403,'OAuth web namespace must deny provider enrollment when OIDC is disabled and reject forged provider POSTs when enabled: /users/auth/openid_connect'); assert.equal((await request('/metrics',{anonymous:true})).status,404); assert.equal((await request('/api/v1/auth/login',{method:'POST',anonymous:true,json:{email:'demo@dawarich.app',password:'safepassword'}})).status,401); assert.equal((await request('/api/v1/auth/login',{method:'POST',anonymous:true,json:{email:values.bootstrap.email,password:'incorrect-owned-fixture'}})).status,401); diff --git a/charts/dawarich/templates/NOTES.txt b/charts/dawarich/templates/NOTES.txt index 6d023c10d..6bab7f701 100644 --- a/charts/dawarich/templates/NOTES.txt +++ b/charts/dawarich/templates/NOTES.txt @@ -63,7 +63,12 @@ An identity fingerprint mismatch or unsafe default seed account blocks startup. kubectl -n {{ .Release.Namespace }} logs deployment/{{ include "dawarich.fullname" . }} -c dawarich kubectl -n {{ .Release.Namespace }} logs deployment/{{ include "dawarich.fullname" . }} -c worker Check dependency credentials, PostGIS extensions, CA trust, writable paths and -the configured public origin. Public self-registration and OAuth routes are closed -by the chart's documented local-account policy. +the configured public origin. Public self-registration is closed by the chart's +documented local-account policy. +{{- if .Values.oidc.enabled }} +OAuth sign-in routes under /users/auth are forwarded; public signup stays closed. +{{- else }} +OAuth routes under /users/auth are closed alongside public signup. +{{- end }} Happy Helmforging :) diff --git a/charts/dawarich/templates/runtime.yaml b/charts/dawarich/templates/runtime.yaml index bd821812d..7ed96a4b5 100644 --- a/charts/dawarich/templates/runtime.yaml +++ b/charts/dawarich/templates/runtime.yaml @@ -28,7 +28,11 @@ data: server_name _; client_max_body_size {{ .Values.proxy.bodySize }}; location ~ ^/api/v1/auth/(register|apple|google)([/.]|$) { return 403; } + {{- if .Values.oidc.enabled }} + location ~ ^/users/sign_up([/.]|$) { return 403; } + {{- else }} location ~ ^/users/(sign_up|auth)([/.]|$) { return 403; } + {{- end }} location ~ ^/metrics([/.]|$) { return 404; } location / { proxy_pass http://127.0.0.1:3010; diff --git a/charts/dawarich/tests/oidc_test.yaml b/charts/dawarich/tests/oidc_test.yaml index 4af6e35c4..3bb9628d5 100644 --- a/charts/dawarich/tests/oidc_test.yaml +++ b/charts/dawarich/tests/oidc_test.yaml @@ -20,6 +20,32 @@ tests: path: stringData.clientSecret value: super-secret + - it: renders the strict nginx policy blocking the oauth web namespace when oidc is disabled + template: templates/runtime.yaml + set: + oidc.enabled: false + asserts: + - matchRegex: + path: data['nginx.conf'] + pattern: 'location ~ \^/users/\(sign_up\|auth\)\(\[/\.\]\|\$\) \{ return 403; \}' + - matchRegex: + path: data['nginx.conf'] + pattern: 'location ~ \^/users/sign_up\(\[/\.\]\|\$\) \{ return 403; \}' + not: true + + - it: renders the nginx policy forwarding the oauth web namespace when oidc is enabled + template: templates/runtime.yaml + set: + oidc.enabled: true + asserts: + - matchRegex: + path: data['nginx.conf'] + pattern: 'location ~ \^/users/sign_up\(\[/\.\]\|\$\) \{ return 403; \}' + - matchRegex: + path: data['nginx.conf'] + pattern: 'location ~ \^/users/\(sign_up\|auth\)\(\[/\.\]\|\$\) \{ return 403; \}' + not: true + - it: injects OIDC environment variables into web and worker workloads template: templates/deployment.yaml set: