mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-26 09:02:11 +03:00
feat(auth): add OIDC password-login disabler when OIDC is active (#10889)
Validado no worktree combinado: typecheck:core, changelog-integrity, complexity, cognitive-complexity, file-size, lint e testes focados (auth-login-route, login-bootstrap-route, feature-flags-settings — corrigi EXPECTED_FEATURE_FLAG_COUNT 51→52 fix-in-place, novo flag adicionado sem atualizar a própria contagem) todos verdes. CI vermelho é o base-red já rastreado em #9985. Obrigado!
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getAuditRequestContext, logAuditEvent } from "@/lib/compliance/index";
|
||||
import { classifyIpScope } from "@/lib/ipUtils";
|
||||
import { getCachedSettings } from "@/lib/localDb";
|
||||
import { getCachedSettings } from "@/lib/db/settings";
|
||||
import { SignJWT } from "jose";
|
||||
import { cookies } from "next/headers";
|
||||
import {
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
getStoredManagementPassword,
|
||||
verifyManagementPassword,
|
||||
} from "@/lib/auth/managementPassword";
|
||||
import { isFeatureFlagEnabled } from "@/shared/utils/featureFlags";
|
||||
import { loginSchema } from "@/shared/validation/schemas";
|
||||
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
|
||||
import { checkLoginGuard, clearLoginAttempts, recordLoginFailure } from "@/server/auth/loginGuard";
|
||||
@@ -74,8 +75,32 @@ export async function POST(request) {
|
||||
return NextResponse.json({ error: "Invalid password payload" }, { status: 400 });
|
||||
}
|
||||
const settings = await getCachedSettings();
|
||||
const bruteForceEnabled = settings.bruteForceProtection !== false;
|
||||
const clientIp = auditContext.ipAddress || null;
|
||||
const oidcDisabledPassword =
|
||||
settings.oidcEnabled === true &&
|
||||
(settings.oidcDisablePasswordLogin === true ||
|
||||
isFeatureFlagEnabled("OMNIROUTE_OIDC_DISABLE_PASSWORD_LOGIN") ||
|
||||
process.env.OMNIROUTE_OIDC_DISABLE_PASSWORD_LOGIN === "true" ||
|
||||
process.env.OIDC_DISABLE_PASSWORD_LOGIN === "true");
|
||||
|
||||
if (oidcDisabledPassword) {
|
||||
logAuditEvent({
|
||||
action: "auth.login.password_disabled_by_oidc",
|
||||
actor: "anonymous",
|
||||
target: "dashboard-auth",
|
||||
resourceType: "auth_session",
|
||||
status: "failed",
|
||||
ipAddress: clientIp || undefined,
|
||||
requestId: auditContext.requestId,
|
||||
metadata: { reason: "password_login_disabled_when_oidc_active" },
|
||||
});
|
||||
return NextResponse.json(
|
||||
{ error: "Password login is disabled when OIDC is active. Please sign in with OIDC." },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const bruteForceEnabled = settings.bruteForceProtection !== false;
|
||||
|
||||
const guardCheck = checkLoginGuard(clientIp, { enabled: bruteForceEnabled });
|
||||
if (!guardCheck.allowed) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { cookies } from "next/headers";
|
||||
import { jwtVerify } from "jose";
|
||||
import { getSettings, updateSettings } from "@/lib/localDb";
|
||||
import { isFeatureFlagEnabled } from "@/shared/utils/featureFlags";
|
||||
import { getSettings, updateSettings } from "@/lib/db/settings";
|
||||
import {
|
||||
hasManagementPasswordConfigured,
|
||||
hashManagementPassword,
|
||||
@@ -52,12 +53,19 @@ export async function GET() {
|
||||
const hasPassword = hasManagementPasswordConfigured(settings);
|
||||
const setupComplete = !!settings.setupComplete;
|
||||
const oidcEnabled = !!settings.oidcEnabled;
|
||||
const oidcDisablePasswordLogin =
|
||||
oidcEnabled &&
|
||||
(settings.oidcDisablePasswordLogin === true ||
|
||||
isFeatureFlagEnabled("OMNIROUTE_OIDC_DISABLE_PASSWORD_LOGIN") ||
|
||||
process.env.OMNIROUTE_OIDC_DISABLE_PASSWORD_LOGIN === "true" ||
|
||||
process.env.OIDC_DISABLE_PASSWORD_LOGIN === "true");
|
||||
return NextResponse.json({
|
||||
authenticated,
|
||||
requireLogin,
|
||||
hasPassword,
|
||||
setupComplete,
|
||||
oidcEnabled,
|
||||
oidcDisablePasswordLogin,
|
||||
...nodeInfo,
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -69,6 +77,7 @@ export async function GET() {
|
||||
hasPassword: true,
|
||||
setupComplete: true,
|
||||
oidcEnabled: false,
|
||||
oidcDisablePasswordLogin: false,
|
||||
...nodeInfo,
|
||||
},
|
||||
{ status: 200 }
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { getSettings, getSettingsRevision, updateSettings } from "@/lib/localDb";
|
||||
import { SettingsRevisionConflictError } from "@/lib/db/settings";
|
||||
import {
|
||||
getSettings,
|
||||
getSettingsRevision,
|
||||
updateSettings,
|
||||
SettingsRevisionConflictError,
|
||||
} from "@/lib/db/settings";
|
||||
import { getRuntimePorts } from "@/lib/runtime/ports";
|
||||
import { updateSettingsSchema } from "@/shared/validation/settingsSchemas";
|
||||
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
|
||||
@@ -118,6 +122,7 @@ const SECURITY_IMPACTING_KEYS = [
|
||||
"requireLogin",
|
||||
"newPassword",
|
||||
"oidcEnabled",
|
||||
"oidcDisablePasswordLogin",
|
||||
"oidcClientSecret",
|
||||
] as const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user