mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
feat(auth): split OIDC_ONLY into granular auth toggles
Replaces the coarse oidc_only + allow_registration settings with four independent toggles: password_login, password_registration, oidc_login, oidc_registration. Each can be enabled/disabled individually in Admin > Settings without affecting the others. - Add resolveAuthToggles() in authService.ts as the central resolver; falls back to legacy oidc_only/allow_registration keys when new keys are absent (backward compat) - OIDC_ONLY env var still works and overrides DB toggles for password_*, with a visual lock in the admin UI when active - Server enforces lockout prevention: cannot disable all login methods - oidc_login gate added to OIDC /login and /callback routes - Remove oidc_only toggle from OIDC settings panel; replaced by the granular toggles in the Settings tab - Add 6 new resolveAuthToggles() unit tests; fix AUTH-DB-033 error message assertion - Update OIDC_ONLY descriptions in README, docker-compose, Helm values, Unraid template, and .env.example to clarify override semantics Closes #492
This commit is contained in:
@@ -77,6 +77,7 @@ import {
|
||||
getAppSettings,
|
||||
validateKeys,
|
||||
isOidcOnlyMode,
|
||||
resolveAuthToggles,
|
||||
setupMfa,
|
||||
enableMfa,
|
||||
disableMfa,
|
||||
@@ -322,6 +323,80 @@ describe('isOidcOnlyMode', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// resolveAuthToggles
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('resolveAuthToggles', () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
testDb.prepare("DELETE FROM app_settings WHERE key IN ('password_login','password_registration','oidc_login','oidc_registration','oidc_only','allow_registration')").run();
|
||||
});
|
||||
|
||||
it('AUTH-DB-022a: returns all true by default (no DB keys, no env override)', () => {
|
||||
vi.stubEnv('OIDC_ONLY', '');
|
||||
const t = resolveAuthToggles();
|
||||
expect(t.password_login).toBe(true);
|
||||
expect(t.password_registration).toBe(true);
|
||||
expect(t.oidc_login).toBe(true);
|
||||
expect(t.oidc_registration).toBe(true);
|
||||
});
|
||||
|
||||
it('AUTH-DB-022b: legacy — OIDC_ONLY=true with OIDC configured disables password_login and password_registration', () => {
|
||||
vi.stubEnv('OIDC_ONLY', 'true');
|
||||
vi.stubEnv('OIDC_ISSUER', 'https://sso.example.com');
|
||||
vi.stubEnv('OIDC_CLIENT_ID', 'trek-client');
|
||||
const t = resolveAuthToggles();
|
||||
expect(t.password_login).toBe(false);
|
||||
expect(t.password_registration).toBe(false);
|
||||
expect(t.oidc_login).toBe(true);
|
||||
expect(t.oidc_registration).toBe(true);
|
||||
});
|
||||
|
||||
it('AUTH-DB-022c: legacy — allow_registration=false disables both password and oidc registration', () => {
|
||||
vi.stubEnv('OIDC_ONLY', '');
|
||||
testDb.prepare("INSERT OR REPLACE INTO app_settings (key, value) VALUES ('allow_registration', 'false')").run();
|
||||
const t = resolveAuthToggles();
|
||||
expect(t.password_login).toBe(true);
|
||||
expect(t.password_registration).toBe(false);
|
||||
expect(t.oidc_login).toBe(true);
|
||||
expect(t.oidc_registration).toBe(false);
|
||||
});
|
||||
|
||||
it('AUTH-DB-022d: new granular keys take precedence over legacy keys', () => {
|
||||
vi.stubEnv('OIDC_ONLY', '');
|
||||
testDb.prepare("INSERT OR REPLACE INTO app_settings (key, value) VALUES ('allow_registration', 'false')").run();
|
||||
testDb.prepare("INSERT OR REPLACE INTO app_settings (key, value) VALUES ('password_registration', 'true')").run();
|
||||
const t = resolveAuthToggles();
|
||||
// New key present → use new keys, allow_registration ignored
|
||||
expect(t.password_registration).toBe(true);
|
||||
expect(t.oidc_registration).toBe(true); // defaults to true when key not set
|
||||
});
|
||||
|
||||
it('AUTH-DB-022e: OIDC_ONLY env var overrides new granular keys for password toggles', () => {
|
||||
vi.stubEnv('OIDC_ONLY', 'true');
|
||||
testDb.prepare("INSERT OR REPLACE INTO app_settings (key, value) VALUES ('password_login', 'true')").run();
|
||||
testDb.prepare("INSERT OR REPLACE INTO app_settings (key, value) VALUES ('password_registration', 'true')").run();
|
||||
const t = resolveAuthToggles();
|
||||
// OIDC_ONLY forces password toggles off even when DB says true
|
||||
expect(t.password_login).toBe(false);
|
||||
expect(t.password_registration).toBe(false);
|
||||
});
|
||||
|
||||
it('AUTH-DB-022f: individual granular keys can be set independently', () => {
|
||||
vi.stubEnv('OIDC_ONLY', '');
|
||||
testDb.prepare("INSERT OR REPLACE INTO app_settings (key, value) VALUES ('password_login', 'true')").run();
|
||||
testDb.prepare("INSERT OR REPLACE INTO app_settings (key, value) VALUES ('password_registration', 'false')").run();
|
||||
testDb.prepare("INSERT OR REPLACE INTO app_settings (key, value) VALUES ('oidc_login', 'true')").run();
|
||||
testDb.prepare("INSERT OR REPLACE INTO app_settings (key, value) VALUES ('oidc_registration', 'false')").run();
|
||||
const t = resolveAuthToggles();
|
||||
expect(t.password_login).toBe(true);
|
||||
expect(t.password_registration).toBe(false);
|
||||
expect(t.oidc_login).toBe(true);
|
||||
expect(t.oidc_registration).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// setupMfa
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -454,7 +529,7 @@ describe('registerUser — OIDC-only / registration-disabled', () => {
|
||||
|
||||
const result = registerUser({ username: 'u', email: 'new@x.com', password: 'Secure123!' });
|
||||
expect(result.status).toBe(403);
|
||||
expect(result.error).toMatch(/SSO/i);
|
||||
expect(result.error).toMatch(/password registration is disabled/i);
|
||||
});
|
||||
|
||||
it('AUTH-DB-034: returns 403 when registration is disabled and no invite', () => {
|
||||
|
||||
Reference in New Issue
Block a user