Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-10-29 20:15:06 +01:00
parent 9d682f85df
commit fbd2dc115d

View File

@@ -1,54 +1,29 @@
-- Add SAML authentication support
-- This migration adds SAML SSO functionality including:
-- - SAML configurations per organization
-- - SAML request/assertion tracking for security
-- - Domain verification
-- - User SAML subject tracking
-- Create ENUM for SAML enforcement policies
CREATE TYPE saml_enforcement_policy AS ENUM (
'OFF', -- SAML disabled, must use password
'OPTIONAL', -- SAML available but not required (default)
'REQUIRED' -- Everyone must use SAML
'OFF',
'OPTIONAL',
'REQUIRED'
);
-- Create auth_saml_configurations table
CREATE TABLE auth_saml_configurations (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
organization_id TEXT NOT NULL,
email_domain TEXT NOT NULL,
-- SAML enabled flag
enabled BOOLEAN NOT NULL DEFAULT false,
-- Enforcement policy for this SAML configuration
enforcement_policy saml_enforcement_policy NOT NULL,
-- Identity Provider (IdP) configuration
idp_entity_id TEXT NOT NULL,
idp_sso_url TEXT NOT NULL,
idp_certificate TEXT NOT NULL, -- X.509 certificate (PEM format)
idp_metadata_url TEXT, -- Optional: for auto-refresh
-- Attribute mapping configuration (using WS-Federation Claims)
idp_certificate TEXT NOT NULL,
idp_metadata_url TEXT,
attribute_email TEXT NOT NULL DEFAULT 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress',
attribute_firstname TEXT NOT NULL DEFAULT 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname',
attribute_lastname TEXT NOT NULL DEFAULT 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname',
attribute_role TEXT NOT NULL DEFAULT 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role',
-- Default role if mapping fails or attribute missing
default_role TEXT NOT NULL DEFAULT 'MEMBER',
-- Auto-signup settings
auto_signup_enabled BOOLEAN NOT NULL DEFAULT false,
-- Domain verification fields
domain_verified BOOLEAN NOT NULL DEFAULT false,
domain_verification_token TEXT,
domain_verified_at TIMESTAMP,
-- Timestamps
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL,
@@ -56,63 +31,47 @@ CREATE TABLE auth_saml_configurations (
REFERENCES organizations(id) ON DELETE CASCADE
);
-- Index for fast organization lookup
CREATE INDEX idx_auth_saml_configurations_organization_id
ON auth_saml_configurations(organization_id);
-- Index for tenant scoping
CREATE INDEX idx_auth_saml_configurations_tenant_id
ON auth_saml_configurations(tenant_id);
-- Unique constraint scoped to organization
-- This allows the same domain in different organizations
-- while preventing duplicates within the same organization
CREATE UNIQUE INDEX idx_saml_config_domain_org_unique
ON auth_saml_configurations(organization_id, email_domain)
WHERE enabled = true AND domain_verified = true;
-- Index for fast domain lookup (for email-based SAML discovery)
CREATE INDEX idx_saml_config_email_domain
ON auth_saml_configurations(email_domain)
WHERE enabled = true AND domain_verified = true;
-- Add SAML subject to users table for tracking SAML NameID
ALTER TABLE users ADD COLUMN saml_subject TEXT;
-- Unique constraint: one SAML subject globally
CREATE UNIQUE INDEX idx_users_saml_subject
ON users(saml_subject)
WHERE saml_subject IS NOT NULL;
-- Make hashed_password nullable for SAML users
-- SAML users authenticate via IdP and don't have passwords
ALTER TABLE users ALTER COLUMN hashed_password DROP NOT NULL;
-- Create auth_saml_assertions table for replay attack prevention
CREATE TABLE auth_saml_assertions (
id TEXT PRIMARY KEY, -- SAML Assertion ID
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
organization_id TEXT NOT NULL,
used_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP NOT NULL
);
-- Index for cleanup of expired assertions
CREATE INDEX idx_auth_saml_assertions_expires_at
ON auth_saml_assertions(expires_at);
-- Index for organization lookup
CREATE INDEX idx_auth_saml_assertions_organization_id
ON auth_saml_assertions(organization_id);
-- Index for tenant scoping
CREATE INDEX idx_auth_saml_assertions_tenant_id
ON auth_saml_assertions(tenant_id);
-- Create auth_saml_requests table for proper InResponseTo validation
-- This prevents replay attacks and validates the SAML authentication flow
CREATE TABLE auth_saml_requests (
id TEXT PRIMARY KEY, -- SAML Request ID generated by SP
id TEXT PRIMARY KEY,
organization_id TEXT NOT NULL,
tenant_id TEXT NOT NULL,
created_at TIMESTAMP NOT NULL,
@@ -122,20 +81,16 @@ CREATE TABLE auth_saml_requests (
REFERENCES organizations(id) ON DELETE CASCADE
);
-- Index for fast request ID lookup during SAML callback
CREATE INDEX idx_auth_saml_requests_id_org ON auth_saml_requests(id, organization_id);
-- Index for cleanup of expired requests
CREATE INDEX idx_auth_saml_requests_expires_at ON auth_saml_requests(expires_at);
-- Create auth_saml_relay_states table for secure RelayState management
-- This prevents organization hijacking attacks
CREATE TABLE auth_saml_relay_states (
token TEXT PRIMARY KEY, -- Cryptographically secure random token
token TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
organization_id TEXT NOT NULL,
request_id TEXT NOT NULL, -- Links to auth_saml_requests.id
saml_config_id TEXT NOT NULL, -- Links to auth_saml_configurations.id
request_id TEXT NOT NULL,
saml_config_id TEXT NOT NULL,
created_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP NOT NULL,
@@ -147,11 +102,8 @@ CREATE TABLE auth_saml_relay_states (
REFERENCES auth_saml_requests(id) ON DELETE CASCADE
);
-- Index for fast token lookup during callback
CREATE INDEX idx_auth_saml_relay_states_token ON auth_saml_relay_states(token);
-- Index for cleanup of expired relay states
CREATE INDEX idx_auth_saml_relay_states_expires_at ON auth_saml_relay_states(expires_at);
-- Index for tenant scoping
CREATE INDEX idx_auth_saml_relay_states_tenant_id ON auth_saml_relay_states(tenant_id);