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)
- IdP signing certificate (
- 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. TheSAML2inner class defines getters forenabled,idpCert,privateKey, and other binding properties (lines 260‑340). -
Saml2Configuration: Located atapp/proprietary/src/main/java/stirling/software/proprietary/security/saml2/Saml2Configuration.java, this Spring@Configurationclass:- Conditionally loads only when
security.saml2.enabled=true(lines 28‑31). - Loads certificates via
CertificateUtilsand constructs aRelyingPartyRegistrationusing URLs derived fromsystem.backendUrl(lines 102‑118). - Registers an
OpenSaml5AuthenticationRequestResolverthat injects uniqueAuthnRequestIDs and relay state (lines 69‑80).
- Conditionally loads only when
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:
- Generates an SP key pair (
saml-private-key.key/saml-public-cert.crt). - Launches Keycloak with the
KEYCLOAK_SAMLservice profile. - 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.ymlproperties mapped toApplicationProperties.Security.SAML2. - Four cryptographic files are mandatory: IdP signing certificate, SP private key, SP public certificate, and the IdP metadata URI.
- The
Saml2Configurationbean constructs the Spring SecurityRelyingPartyRegistrationonly whensecurity.saml2.enabled=true. - Local testing is supported via
testing/compose/docker-compose-keycloak-saml.ymland thestart-saml-test.shhelper script. - The
loginMethod: saml2setting 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →