mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 22:25:24 +00:00
fix: gate second factors after SSO/LDAP behind an admin setting
This commit is contained in:
1 parent
f217d8db89
commit
95abe24798
13 files changed
+307
-5
No files matched your search
@@ -256,6 +256,33 @@ export async function updateOidcAutoProvision(
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSecondFactorAfterExternalLogin(): Promise<{
|
||||
enabled: boolean;
|
||||
}> {
|
||||
try {
|
||||
const response = await authApi.get(
|
||||
"/users/second-factor-after-external-login",
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
handleApiError(error, "check second factor after external login status");
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateSecondFactorAfterExternalLogin(
|
||||
enabled: boolean,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await authApi.patch(
|
||||
"/users/second-factor-after-external-login",
|
||||
{ enabled },
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
handleApiError(error, "update second factor after external login");
|
||||
}
|
||||
}
|
||||
|
||||
export async function getOidcSilentLoginDefault(): Promise<{
|
||||
enabled: boolean;
|
||||
locked?: boolean;
|
||||
|
||||
@@ -2884,6 +2884,8 @@
|
||||
"allowPasswordLoginDesc": "Username/password login",
|
||||
"oidcAutoProvision": "OIDC Auto-Provision",
|
||||
"oidcAutoProvisionDesc": "Auto-create accounts for OIDC/SSO users on first login (independent of the registration toggle)",
|
||||
"secondFactorAfterExternalLogin": "Ask for a second factor after external logins (SSO, GitHub, Google, LDAP)",
|
||||
"secondFactorAfterExternalLoginDesc": "Off, an enrolled second factor is only asked for after password and other local logins, same as before. On, it is asked for after every login method, including SSO and LDAP.",
|
||||
"oidcSilentLoginDefault": "Silent OIDC Login by Default",
|
||||
"oidcSilentLoginDefaultDesc": "Automatically redirect to OIDC login on every visit, skipping the login form entirely",
|
||||
"oidcSilentLoginDefaultLockedDesc": "This setting is locked by the OIDC_SILENT_LOGIN_DEFAULT environment variable and cannot be changed here.",
|
||||
@@ -3054,6 +3056,7 @@
|
||||
"updatePasswordLoginFailed": "Failed to update password login setting",
|
||||
"cannotDisablePasswordLoginWithTotp": "Cannot disable password login while 2FA is enabled for one or more users. Disable 2FA first.",
|
||||
"updateOidcAutoProvisionFailed": "Failed to update OIDC auto-provision setting",
|
||||
"updateSecondFactorAfterExternalLoginFailed": "Failed to update second factor setting",
|
||||
"updateOidcSilentLoginDefaultFailed": "Failed to update silent OIDC login setting",
|
||||
"updatePasswordResetFailed": "Failed to update password reset setting",
|
||||
"sessionTimeoutRange2": "Session timeout must be between 1 and 720 hours",
|
||||
|
||||
@@ -2054,6 +2054,8 @@ export {
|
||||
updateRegistrationAllowed,
|
||||
getOidcAutoProvision,
|
||||
updateOidcAutoProvision,
|
||||
getSecondFactorAfterExternalLogin,
|
||||
updateSecondFactorAfterExternalLogin,
|
||||
getOidcSilentLoginDefault,
|
||||
updateOidcSilentLoginDefault,
|
||||
updatePasswordLoginAllowed,
|
||||
|
||||
@@ -37,6 +37,8 @@ import {
|
||||
updateGuacamoleSettings,
|
||||
getOidcAutoProvision,
|
||||
updateOidcAutoProvision,
|
||||
getSecondFactorAfterExternalLogin,
|
||||
updateSecondFactorAfterExternalLogin,
|
||||
getOidcSilentLoginDefault,
|
||||
updateOidcSilentLoginDefault,
|
||||
getCommandHistoryEnabled,
|
||||
@@ -223,6 +225,8 @@ export function AdminSettingsPanel({
|
||||
|
||||
// SSO / auto-provision state
|
||||
const [oidcAutoProvision, setOidcAutoProvision] = useState(false);
|
||||
const [secondFactorAfterExternalLogin, setSecondFactorAfterExternalLogin] =
|
||||
useState(false);
|
||||
const [oidcSilentLoginDefault, setOidcSilentLoginDefault] = useState(false);
|
||||
const [ssoProviders, setSsoProviders] = useState<SSOProvider[]>([]);
|
||||
const [ssoDialogOpen, setSsoDialogOpen] = useState(false);
|
||||
@@ -394,6 +398,7 @@ export function AdminSettingsPanel({
|
||||
level,
|
||||
guac,
|
||||
oidcProv,
|
||||
secondFactorExternal,
|
||||
oidcSilent,
|
||||
cmdHistory,
|
||||
analytics,
|
||||
@@ -413,6 +418,7 @@ export function AdminSettingsPanel({
|
||||
getLogLevel(),
|
||||
getGuacamoleSettings(),
|
||||
getOidcAutoProvision(),
|
||||
getSecondFactorAfterExternalLogin(),
|
||||
getOidcSilentLoginDefault(),
|
||||
getCommandHistoryEnabled(),
|
||||
getAnalyticsEnabled(),
|
||||
@@ -435,6 +441,8 @@ export function AdminSettingsPanel({
|
||||
}
|
||||
if (oidcProv.status === "fulfilled")
|
||||
setOidcAutoProvision(oidcProv.value.enabled);
|
||||
if (secondFactorExternal.status === "fulfilled")
|
||||
setSecondFactorAfterExternalLogin(secondFactorExternal.value.enabled);
|
||||
if (oidcSilent.status === "fulfilled") {
|
||||
setOidcSilentLoginDefault(oidcSilent.value.enabled);
|
||||
setOidcSilentLoginDefaultLocked(oidcSilent.value.locked ?? false);
|
||||
@@ -555,6 +563,17 @@ export function AdminSettingsPanel({
|
||||
}
|
||||
}
|
||||
|
||||
async function handleToggleSecondFactorAfterExternalLogin() {
|
||||
const newVal = !secondFactorAfterExternalLogin;
|
||||
setSecondFactorAfterExternalLogin(newVal);
|
||||
try {
|
||||
await updateSecondFactorAfterExternalLogin(newVal);
|
||||
} catch {
|
||||
setSecondFactorAfterExternalLogin(!newVal);
|
||||
toast.error(t("admin.updateSecondFactorAfterExternalLoginFailed"));
|
||||
}
|
||||
}
|
||||
|
||||
async function handleToggleOidcSilentLoginDefault() {
|
||||
if (oidcSilentLoginDefaultLocked) return;
|
||||
const newVal = !oidcSilentLoginDefault;
|
||||
@@ -1233,6 +1252,10 @@ export function AdminSettingsPanel({
|
||||
handleTogglePasswordLogin={handleTogglePasswordLogin}
|
||||
oidcAutoProvision={oidcAutoProvision}
|
||||
handleToggleOidcAutoProvision={handleToggleOidcAutoProvision}
|
||||
secondFactorAfterExternalLogin={secondFactorAfterExternalLogin}
|
||||
handleToggleSecondFactorAfterExternalLogin={
|
||||
handleToggleSecondFactorAfterExternalLogin
|
||||
}
|
||||
oidcSilentLoginDefault={oidcSilentLoginDefault}
|
||||
oidcSilentLoginDefaultLocked={oidcSilentLoginDefaultLocked}
|
||||
handleToggleOidcSilentLoginDefault={handleToggleOidcSilentLoginDefault}
|
||||
|
||||
@@ -47,6 +47,8 @@ type GeneralSettingsSectionProps = {
|
||||
handleTogglePasswordLogin: () => void;
|
||||
oidcAutoProvision: boolean;
|
||||
handleToggleOidcAutoProvision: () => void;
|
||||
secondFactorAfterExternalLogin: boolean;
|
||||
handleToggleSecondFactorAfterExternalLogin: () => void;
|
||||
oidcSilentLoginDefault: boolean;
|
||||
oidcSilentLoginDefaultLocked: boolean;
|
||||
handleToggleOidcSilentLoginDefault: () => void;
|
||||
@@ -98,6 +100,8 @@ export function AdminGeneralSettingsSection({
|
||||
handleTogglePasswordLogin,
|
||||
oidcAutoProvision,
|
||||
handleToggleOidcAutoProvision,
|
||||
secondFactorAfterExternalLogin,
|
||||
handleToggleSecondFactorAfterExternalLogin,
|
||||
oidcSilentLoginDefault,
|
||||
oidcSilentLoginDefaultLocked,
|
||||
handleToggleOidcSilentLoginDefault,
|
||||
@@ -301,6 +305,15 @@ export function AdminGeneralSettingsSection({
|
||||
onToggle={handleToggleOidcAutoProvision}
|
||||
/>
|
||||
</SettingRow>
|
||||
<SettingRow
|
||||
label={t("admin.secondFactorAfterExternalLogin")}
|
||||
description={t("admin.secondFactorAfterExternalLoginDesc")}
|
||||
>
|
||||
<AdminToggle
|
||||
on={secondFactorAfterExternalLogin}
|
||||
onToggle={handleToggleSecondFactorAfterExternalLogin}
|
||||
/>
|
||||
</SettingRow>
|
||||
<SettingRow
|
||||
label={t("admin.oidcSilentLoginDefault")}
|
||||
description={
|
||||
|
||||
Reference in new issue
Block a user