SAML Flow

Overview

Two separate SAML integrations exist:

Integration

Purpose

Endpoints

Use Case

Site SAML

Pub lic/internal site access

/saml/*

Employee intranet, gated content

CMS SAML

Admin CMS access

/saml/cms/*

Content editors, a dministrators


Site SAML Flow

Provides SSO for internal/external site separation. Employees access internal content; public users see external content.

Architecture

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   External  │     │   Internal  │     │     IdP     │
│    Site     │     │    Site     │     │   (Entra)   │
│ logout-dest │     │ login-dest  │     │             │
└──────┬──────┘     └──────┬──────┘     └──────┬──────┘
       │                   │                   │
       │    /saml/auth     │                   │
       │◄─────────────────►│                   │
       │  (routing check)  │                   │
       │                   │                   │
       │                   │   /saml/login     │
       │                   │──────────────────►│
       │                   │   AuthnRequest    │
       │                   │                   │
       │                   │   /saml/response  │
       │                   │◄──────────────────│
       │                   │   SAMLResponse    │
       │                   │                   │
       │   /saml/logout    │                   │
       │◄──────────────────│──────────────────►│
       │                   │   LogoutRequest   │
       │                   │                   │

Login Flow

1. User visits internal site (login-destination domain)
         │
         ▼
2. /saml/auth checks auth cookie
         │
         ├─► Has cookie + valid assertion → Allow access
         │
         └─► No cookie → Redirect to /saml/login
                   │
                   ▼
3. /saml/login generates AuthnRequest
   - Creates XML with unique ID, timestamp
   - Encodes: XML → Deflate → Base64 → URL-encode
   - Redirects to IdP endpoint
         │
         ▼
4. User authenticates at IdP
         │
         ▼
5. IdP POSTs to /saml/response
   - SAMLResponse (encrypted assertion)
   - RelayState (original URL)
         │
         ▼
6. /saml/response validates
   - Decrypts assertion (RSA-OAEP + AES-256-CBC)
   - Validates issuer, timestamps
   - Checks replay (assertion ID uniqueness)
         │
         ▼
7. Creates/updates user, sets auth cookie
         │
         ▼
8. Redirects to RelayState or login-destination

Logout Flow

1. User clicks logout on internal site
         │
         ▼
2. /saml/logout
   - Requires authenticated user
   - Creates LogoutRequest XML
   - Signs with RSA-SHA256
   - Deletes auth cookie
         │
         ▼
3. Redirects to IdP with signed LogoutRequest
         │
         ▼
4. IdP terminates session
         │
         ▼
5. User lands on logout-destination (external site)

Domain Routing (/saml/auth)

The /saml/auth endpoint enforces access control based on domain:

Current Domain

Auth Status

Action

login-destination (internal)

Not authenticated

→ Redirect to IdP

login-destination (internal)

Authenticated

→ Allow

logout-destination (external)

Authenticated

→ Redirect to internal

logout-destination (external)

Not authenticated

→ Allow


CMS SAML Flow

Provides SSO for CMS admin access with role-based authorization.

Architecture

┌─────────────┐                         ┌─────────────┐
│     CMS     │                         │     IdP     │
│  /cms/...   │                         │  (Azure AD) │
└──────┬──────┘                         └──────┬──────┘
       │                                       │
       │         GET /saml/cms/login           │
       │──────────────────────────────────────►│
       │         AuthnRequest                  │
       │                                       │
       │         POST /saml/cms/login          │
       │◄──────────────────────────────────────│
       │         SAMLResponse                  │
       │                                       │
       │         POST /saml/cms/logout         │
       │◄──────────────────────────────────────│
       │         LogoutResponse                │
       │                                       │

Login Flow

1. User visits CMS without session
         │
         ▼
2. Redirected to GET /saml/cms/login
   - Creates AuthnRequest with SP issuer
   - Redirects to IdP
         │
         ▼
3. User authenticates at IdP
         │
         ▼
4. IdP POSTs to /saml/cms/login
   - SAMLResponse with user attributes
         │
         ▼
5. /saml/cms/login validates
   - Decrypts assertion
   - Validates issuer, timestamps
   - Checks replay attack
         │
         ▼
6. Extracts attributes using configured identifiers
   - first-name-identifier → firstName
   - last-name-identifier  → lastName
   - user-identifier       → email
   - role-identifier       → roles
         │
         ▼
7. Role validation
   - Extracts user's role from assertion
   - Checks if role exists in configured `roles` list
         │
         ├─► Role matches → Continue
         │
         └─► No match → 403 Forbidden
                   │
                   ▼
8. User provisioning
   - Creates or updates user with attributes
   - Assigns to CMS user group
   - Sets country to Netherlands
         │
         ▼
9. Sets session (_ID key), redirects to CMS

Key Differences from Site SAML

Aspect

Site SAML

CMS SAML

Authorization*

Any authenticated user

Role must match roles list

Attributes

Project-hardcoded mapping

Configurable identifiers

User groups

Internal website groups

CMS user group

Certificates

saml-private-key.pem

saml- cms-private-key.pem

Session

Auth cookie

_ID session key

Logout

SP-initiated, signed

IdP-initiated only