How to Configure SAML Single Sign-On (SSO) in Stirling-PDF

To configure SAML single sign-on (SSO) in Stirling-PDF, enable the feature in settings.yml by setting security.saml2.enabled: true, provide your Identity Provider certificate and Service Provider key pair, and set loginMethod: saml2 to redirect users to your IdP (e.g., Keycloak, Okta, or Azure AD).

Stirling-PDF supports enterprise-grade SAML 2.0 authentication through its Spring Boot 3 security layer, allowing organizations to integrate with corporate identity providers. This guide demonstrates how to wire the ApplicationProperties configuration class to activate SSO, using actual implementation details from the Stirling-Tools/Stirling-PDF repository.

Prerequisites for SAML 2.0 Integration

Before modifying configuration files, ensure your environment meets these requirements:

  • Enterprise License: The SAML provider is gated behind the Enterprise tier (AuthenticationType.SAML2).
  • Identity Provider: An IdP supporting SAML 2.0 (Keycloak, Okta, Azure AD, etc.).
  • Cryptographic Material:
    • IdP signing certificate (idpCert)
    • Service Provider private key (privateKey)
    • Service Provider public certificate (spCert)
  • Backend URL: The public URL where Stirling-PDF is reachable (system.backendUrl), required for generating metadata and Assertion Consumer Service (ACS) endpoints.

Enabling SAML SSO in settings.yml

Add the following configuration to settings.yml (or inject via environment variables/Docker -e flags):

security:
  saml2:
    enabled: true              # Activates the SAML2AuthenticationProvider

    provider: keycloak         # Display name for the UI

    registrationId: stirling   # Must match the RelyingPartyRegistration ID

    autoCreateUser: true       # Provisions local accounts on first login

    blockRegistration: false   # Disables self-service registration via SAML

    idpMetadataUri: "https://idp.example.com/realms/stirling/protocol/saml/descriptor"
    idpCert: "/opt/stirling/config/idp-signing-cert.pem"
    privateKey: "/opt/stirling/config/sp-private-key.key"
    spCert: "/opt/stirling/config/sp-public-cert.crt"
    idpIssuer: "https://idp.example.com/realms/stirling"
    idpSingleLoginUrl: "https://idp.example.com/realms/stirling/protocol/saml"
    idpSingleLogoutUrl: "https://idp.example.com/realms/stirling/protocol/saml"

system:
  backendUrl: "https://pdf.mycompany.com"

loginMethod: saml2           # Optional: forces SAML-only authentication

The fields above map directly to the ApplicationProperties.Security.SAML2 inner class defined in app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java (lines 266‑338).

To restrict authentication to SAML only, set the global login method as shown above. The isSaml2Active() method in ApplicationProperties evaluates this flag to determine whether to display the SAML login button.

How the Configuration Is Consumed

The SAML integration relies on two primary components in the proprietary module:

  • ApplicationProperties: Holds the POJO representation of your YAML settings. The SAML2 inner class defines getters for enabled, idpCert, privateKey, and other binding properties (lines 260‑340).

  • Saml2Configuration: Located at app/proprietary/src/main/java/stirling/software/proprietary/security/saml2/Saml2Configuration.java, this Spring @Configuration class:

    • Conditionally loads only when security.saml2.enabled=true (lines 28‑31).
    • Loads certificates via CertificateUtils and constructs a RelyingPartyRegistration using URLs derived from system.backendUrl (lines 102‑118).
    • Registers an OpenSaml5AuthenticationRequestResolver that injects unique AuthnRequest IDs and relay state (lines 69‑80).

Once the YAML is present and the application restarts, the SAML service provider is automatically wired into the Spring Security filter chain.

Testing SAML Locally with Keycloak

Stirling-PDF provides a complete local testing stack under testing/compose/:

File Purpose
testing/compose/docker-compose-keycloak-saml.yml Spins up a pre-configured Keycloak container with the Stirling-PDF SAML client.
testing/compose/keycloak-realm-saml.json Realm definition containing clients, users, and certificates.
testing/compose/start-saml-test.sh Generates self-signed certificates and orchestrates container startup.

Execute the test environment:

cd testing/compose
./start-saml-test.sh --auto

The script performs the following actions:

  1. Generates an SP key pair (saml-private-key.key / saml-public-cert.crt).
  2. Launches Keycloak with the KEYCLOAK_SAML service profile.
  3. Exports the IdP metadata to http://localhost:9080/realms/stirling-saml/protocol/saml/descriptor.

The compose file automatically injects the required environment variables:

SECURITY_SAML2_ENABLED: "true"
SECURITY_SAML2_PROVIDER: "keycloak"
SECURITY_SAML2_REGISTRATIONID: "keycloak"
SECURITY_SAML2_IDP_ISSUER: "http://localhost:9080/realms/stirling-saml"
SECURITY_SAML2_IDP_CERT: "/app/keycloak-saml-cert.pem"
SECURITY_SAML2_PRIVATEKEY: "/app/saml-private-key.key"
SECURITY_SAML2_SP_CERT: "/app/saml-public-cert.crt"
SECURITY_SAML2_SP_ENTITYID: "http://localhost:8080"
SECURITY_SAML2_SP_ACS: "http://localhost:8080/login/saml2/sso/keycloak"

Verify the flow by navigating to http://localhost:8080 and selecting the SAML2 login option, which redirects to the Keycloak authentication page.

Troubleshooting Common SAML Issues

Symptom Root Cause Resolution
"SAML2 IdP certificate not found" The idpCert path in settings.yml points to a missing file or uses an incorrect classpath prefix. Verify the file exists at the specified absolute path and is readable by the container process.
Login button missing The loginMethod property excludes saml2 or security.saml2.enabled is false. Set loginMethod: saml2 (or all) and ensure the enabled flag is true.
Metadata URL returns 404 The idpMetadataUri is unreachable or uses an incorrect scheme. For local testing, use the HTTP descriptor URL; for production, ensure the HTTPS endpoint is publicly accessible.
User auto-creation fails The autoCreateUser flag is disabled or the Enterprise license is inactive. Enable autoCreateUser: true and verify your license status via the application health endpoint.

Enable DEBUG logging for the stirling.software package to view detailed request/response traces from Saml2Configuration and CustomSaml2AuthenticationSuccessHandler.

Summary

  • SAML 2.0 requires an Enterprise license and is configured exclusively through settings.yml properties mapped to ApplicationProperties.Security.SAML2.
  • Four cryptographic files are mandatory: IdP signing certificate, SP private key, SP public certificate, and the IdP metadata URI.
  • The Saml2Configuration bean constructs the Spring Security RelyingPartyRegistration only when security.saml2.enabled=true.
  • Local testing is supported via testing/compose/docker-compose-keycloak-saml.yml and the start-saml-test.sh helper script.
  • The loginMethod: saml2 setting forces exclusive SSO authentication and hides native login forms.

Frequently Asked Questions

Is SAML 2.0 available in the open-source version of Stirling-PDF?

No. According to the source code in ApplicationProperties.java, the SAML2 authentication type is gated behind the Enterprise tier. The Saml2Configuration class resides in the app/proprietary module, which requires a valid enterprise license to activate.

What Identity Providers are compatible with Stirling-PDF SAML configuration?

Any IdP conforming to the SAML 2.0 specification is compatible, including Keycloak, Okta, Azure Active Directory, and Auth0. The configuration in settings.yml accepts standard metadata descriptors and single sign-on/logout URLs regardless of the vendor.

How do I generate the required SAML certificates for Stirling-PDF?

For production, obtain certificates from your organization's Certificate Authority or IdP. For local development, use the start-saml-test.sh script in testing/compose/, which automatically generates a self-signed SP key pair using OpenSSL. The script places saml-private-key.key and saml-public-cert.crt in the compose directory for immediate use.

Why does the SAML login redirect fail after successful authentication?

This typically indicates a mismatch between the system.backendUrl value and the actual public URL. The Saml2Configuration class uses this property to construct the ACS URL (lines 102‑110). If the backend URL is omitted, the application falls back to request-derived URLs, which often fail behind reverse proxies or load balancers. Explicitly set system.backendUrl to the canonical HTTPS address.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →