Files
wekan/models/lib/authenticationMethod.js
Lauri Ojansivu 0314406656 Read login secrets from *_FILE, and let the Admin Panel override DEFAULT_AUTHENTICATION_METHOD.
LDAP_AUTHENTIFICATION_PASSWORD_FILE and OAUTH2_SECRET_FILE were listed in the
Dockerfile, snap, docker-compose and start-wekan since #5724, but no code read
them, so a password could only be an environment variable. WeKan now reads the
file itself, at each login (a rotated secret applies at once), so the password
is never in the environment - the point of Docker / Kubernetes secrets. The
order is the Admin Panel, the variable, then its file; one trailing line break
is dropped. The application code is the same on every platform, so it works in
Docker, the snap (files under /var/snap/wekan/common), bundles, AppImage,
Flatpak, Mac and Windows. Admin Panel / People shows when the password comes
from the file and when the file cannot be read, never the path or content.
The path itself is an environment variable only: settable in the Admin Panel
next to the LDAP host or the OAuth2 token endpoint, it would let the server
read any file and send it there as the password.

DEFAULT_AUTHENTICATION_METHOD is a field of the Login pane's settings form.
Choosing a method overrides the variable; Default gives it back. Before, the
variable rewrote the stored method at every start, so an administrator's
choice was lost on restart. The published method is now the override, else the
variable, else password. On upgrade, a method chosen with the old dropdown
while no variable was set becomes the override, once, so it is not lost. The
old dropdown is removed: two controls for one setting on one page.

The snap key for the LDAP password file was spelled
ldap-authentification-password-file, unlike its siblings and its help text;
it is ldap-authentication-password-file now (it had no effect before).
MAIL_SERVICE_PASSWORD_FILE, MONGO_PASSWORD_FILE and S3_SECRET_FILE are still
not read by WeKan; secrets/README.md says so.

Thanks to Roemer, CrashOverride-lab, ww-daniel-mora and xet7 !
2026-10-05 21:11:12 +03:00

60 lines
2.8 KiB
JavaScript

'use strict';
// Pure, isomorphic helpers for resolving the default login authentication method
// (one of: password, ldap, oauth2, cas, saml). Extracted from the settings model
// so #5879 is unit-testable without Meteor.
//
// #5879 had two halves:
// 1. `DEFAULT_AUTHENTICATION_METHOD` env var was ignored — the stored setting
// was only ever seeded as 'password' and the env value was never applied,
// so operators setting it (Kubernetes/Helm) saw no effect.
// 2. Admin Panel > Layout > Save appeared to hang / not persist: when the
// authentication-method <select> had not populated yet (its options come
// from an async Meteor.call), its value was '' / null, and saving that over
// the required `defaultAuthenticationMethod` string silently failed
// validation — the save looked stuck and nothing changed.
// Both are addressed by never letting an empty value win over a real one.
// Normalize a raw value (env var, <select> value, DB field) to a clean method
// string, or undefined when it carries no usable value. Method keys are
// lowercase (getAuthenticationsEnabled: ldap/oauth2/cas, plus password), so we
// lowercase here too, making DEFAULT_AUTHENTICATION_METHOD=LDAP work.
function normalizeAuthenticationMethod(value) {
if (typeof value !== 'string') return undefined;
const v = value.trim().toLowerCase();
return v.length > 0 ? v : undefined;
}
// First usable method among the candidates, else 'password'. Used to (a) apply
// the DEFAULT_AUTHENTICATION_METHOD env authoritatively at startup and (b) stop
// the Admin Panel Layout save from overwriting the stored method with an empty
// value when the <select> is not populated yet.
function resolveDefaultAuthenticationMethod(preferred, current, fallback = 'password') {
return (
normalizeAuthenticationMethod(preferred) ||
normalizeAuthenticationMethod(current) ||
normalizeAuthenticationMethod(fallback) ||
'password'
);
}
// Once, on upgrade to the Admin Panel override of DEFAULT_AUTHENTICATION_METHOD:
// the method the old Login dropdown stored becomes the override when it was
// the administrator's choice - not 'password' (the seeded default), and not
// with the environment variable set (the start then overwrote the dropdown, so
// the stored value was the variable's). Returns the method to keep as the
// override, or undefined.
function migratedDefaultAuthenticationMethod({ stored, override, environment }) {
const method = normalizeAuthenticationMethod(stored);
if (!method || method === 'password') return undefined;
if (normalizeAuthenticationMethod(override)) return undefined;
if (normalizeAuthenticationMethod(environment)) return undefined;
return method;
}
export {
normalizeAuthenticationMethod,
resolveDefaultAuthenticationMethod,
migratedDefaultAuthenticationMethod,
};