mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat(enterprise): add SAML 2.0 SSO with SP-initiated login
Implements SAML SSO using @node-saml/node-saml, gated behind SAML_ENABLED env var and the saml_sso enterprise license feature. - SAML env vars (entity ID, callback URL, IdP SSO URL, IdP cert, auto-create/auto-link users, default role, provider name, username/email attribute mapping) with validation in superRefine - SAML plugin with three routes: metadata (GET), login (GET), and ACS callback (POST with form-urlencoded content type parser) - Callback uses the shared external-auth resolver for user resolution (same pattern as OIDC: match/link/create/deny) - Auth config endpoint exposes samlEnabled and samlProviderName - Session loginMethod detection updated for SAML auth provider - Frontend login page shows SAML SSO button when enabled - i18n strings for SAML error messages across all 21 locales
This commit is contained in:
+22
-1
@@ -30,6 +30,7 @@ import {
|
||||
ensureDefaultAdmin,
|
||||
} from "./plugins/auth.js";
|
||||
import { oidcRoutes } from "./plugins/oidc.js";
|
||||
import { registerSaml } from "./plugins/saml.js";
|
||||
import { registerStatic } from "./plugins/static.js";
|
||||
import { registerUpload } from "./plugins/upload.js";
|
||||
import { adminOpsRoutes } from "./routes/admin-ops.js";
|
||||
@@ -39,6 +40,7 @@ import { auditLogRoutes } from "./routes/audit-log.js";
|
||||
import { registerBatchRoutes } from "./routes/batch.js";
|
||||
import { configRoutes } from "./routes/config.js";
|
||||
import { docsRoutes } from "./routes/docs.js";
|
||||
import { registerEnterpriseRoutes } from "./routes/enterprise/index.js";
|
||||
import { registerFeatureRoutes } from "./routes/features.js";
|
||||
import { registerFetchUrlsRoute } from "./routes/fetch-urls.js";
|
||||
import { fileRoutes } from "./routes/files.js";
|
||||
@@ -50,7 +52,6 @@ import { settingsRoutes } from "./routes/settings.js";
|
||||
import { teamsRoutes } from "./routes/teams.js";
|
||||
import { registerToolRoutes } from "./routes/tools/index.js";
|
||||
import { userFileRoutes } from "./routes/user-files.js";
|
||||
import { registerEnterpriseRoutes } from "./routes/enterprise/index.js";
|
||||
|
||||
// Run before anything else
|
||||
try {
|
||||
@@ -302,6 +303,9 @@ await authRoutes(app);
|
||||
// OIDC routes
|
||||
await oidcRoutes(app);
|
||||
|
||||
// SAML routes
|
||||
await registerSaml(app);
|
||||
|
||||
// File upload/download routes
|
||||
await fileRoutes(app);
|
||||
|
||||
@@ -417,6 +421,23 @@ app.get("/api/v1/config/auth", async () => {
|
||||
config.oidcProviderName = env.OIDC_PROVIDER_NAME || null;
|
||||
config.oidcLoginUrl = "/api/auth/oidc/login";
|
||||
}
|
||||
|
||||
// SAML SSO requires both env flag and enterprise license
|
||||
let samlLicensed = false;
|
||||
if (env.SAML_ENABLED) {
|
||||
try {
|
||||
const { isFeatureEnabled } = await import("@snapotter/enterprise");
|
||||
samlLicensed = isFeatureEnabled("saml_sso");
|
||||
} catch {
|
||||
// Enterprise package not available
|
||||
}
|
||||
}
|
||||
if (env.SAML_ENABLED && samlLicensed) {
|
||||
config.samlEnabled = true;
|
||||
config.samlProviderName = env.SAML_PROVIDER_NAME || "SSO";
|
||||
config.samlLoginUrl = "/api/auth/saml/login";
|
||||
}
|
||||
|
||||
return config;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user