saml-rs
Pure-Rust SAML 2.0 Service Provider and Identity Provider support. The
protocol layer uses Rust XML parsing and does not require libxml2, xmlsec1,
or an OpenSSL build chain. XML cryptography (XML-DSig, XML-Enc, C14N, detached
message signatures) is delegated to bergshamra
behind the default crypto-bergshamra feature.
[]
= "0.1"
# Crypto-free protocol layer only:
# saml-rs = { version = "0.1", default-features = false }
The project now publishes one crate: saml-rs. The Rust import path is
saml_rs.
Upgrading
saml-rs is currently pre-1.0, so minor releases may contain breaking API or
behavior changes. Before updating across minor versions, review the
migration guides.
Why saml-rs?
saml-rs is aimed at applications that need SAML SP/IdP flows without a C XML
security stack in their build and deployment environment.
| Area | saml-rs |
|---|---|
| Native dependencies | No libxml2, xmlsec1, or OpenSSL build chain for the protocol layer |
| Roles | Service Provider and Identity Provider |
| Bindings | HTTP-POST, HTTP-Redirect, HTTP-POST-SimpleSign |
| Metadata | Parse and generate SP/IdP metadata; verify signed metadata |
| Single Logout | Create and parse LogoutRequest / LogoutResponse |
| Crypto | XML-DSig, XML-Enc, detached signatures via bergshamra |
| Hardening | Request correlation, audience/destination/issuer checks, XSW guards, bounded parsing |
| Unsafe code | #![forbid(unsafe_code)] |
Compared with samael, the main tradeoff is
deployment shape: samael is the established Rust SAML crate and commonly uses
the native xmlsec stack, while saml-rs keeps the SAML protocol path
Rust-only and delegates XML crypto to a Rust crate.
What you can do
| Area | Highlights |
|---|---|
| Web SSO | Signed AuthnRequest / Response, HTTP-POST, HTTP-Redirect, POST-SimpleSign |
| Metadata | Parse peer metadata, generate SP/IdP descriptors, verify signed aggregates |
| Single Logout | Create and parse logout request/response flows across all three bindings |
| Validation | Issuer, audience, destination/recipient, bearer confirmation, status, time windows, request correlation |
| Crypto | XML-DSig sign/verify, XML-Enc encrypt/decrypt, detached message signatures, metadata key pinning |
| Extraction | quick-xml DOM plus local-name field extraction |
Unsupported SAML profiles
The high-level Saml API currently focuses on browser Web SSO, metadata-driven
SP/IdP setup, XML signature/encryption through bergshamra, and Single Logout.
It does not yet implement Artifact resolution, SOAP/back-channel profiles,
ECP/PAOS, SAML query protocols, NameID management, or metadata federation. If
you need one of those profiles for a real interoperability target, please open
an issue with the profile, binding, IdP/SP product, and a minimal expected flow
so we can consider the implementation.
Quick Start
The primary API is the typed Saml facade. Build local SP/IdP configuration
with SpConfig::builder and IdpConfig::builder, import peer metadata into
typed descriptors, and keep the returned Pending<_> value with your browser
session while the SAML round trip is in flight.
Runnable typed SSO
A signed SP -> IdP -> SP round trip is available as an executable example:
Source: examples/sso.rs.
The repository also includes a typed Single Logout walkthrough in
examples/slo.rs and a low-level compatibility walkthrough
in examples/raw_compat.rs.
The crate-root docs contain
doctested fragments for the typed Saml facade, including
Saml<Sp>::start_sso,
Saml<Sp>::finish_sso,
Saml<Idp>::receive_sso,
and Saml<Sp>::finish_slo.
Those rustdoc snippets are compiled by cargo test --doc; the README stays as
an entry point and links to the complete examples above.
Service Provider SSO flow
- Build local SP state with
SpConfig::builderandSaml::sp. - Import peer IdP metadata into
IdpDescriptor. - Start SSO with
sp.start_sso(...)and storestarted.pendingwith the browser session. - In the ACS handler, pass the posted response fields and the matching pending
value to
sp.finish_sso(...).
See examples/sso.rs for a complete signed SP -> IdP -> SP
round trip and the doctested crate-root SSO
fragment for the
compact API shape.
Identity Provider - receive and respond
The IdP side mirrors the SP flow: import peer SP metadata into SpDescriptor,
parse an AuthnRequest with idp.receive_sso(...), then produce a typed
browser response with idp.respond_sso(...). The complete path is exercised in
examples/sso.rs, and the short rustdoc version is in the
Identity Provider flows
crate-root section.
Single Logout
Typed Single Logout starts from session.logout_subject(), stores the
PendingLogoutRequest, and finishes only with the matching LogoutResponse.
Peer-initiated logout uses Received<LogoutRequest> rather than free-form
request ID strings. See examples/slo.rs for the complete
typed walkthrough and the doctested SLO
fragment for the compact
shape.
Metadata
Metadata trust is explicit. The rustdoc
Metadata trust
section describes production-shaped signed metadata validation with pinned
certificates. MetadataTrustPolicy::UnsignedForCompatibility is available for
legacy interoperability, but it is a compatibility exception rather than a
production default.
The compact rustdoc flow snippets use
ReplayPolicy::DisabledForCompatibility only to keep examples dependency-free.
Production inbound validation should use ReplayPolicy::RequireCache with a
caller-owned replay cache and the retention guidance in
SamlValidationContext.
Advanced/raw compatibility
The low-level compatibility API remains available under saml_rs::raw for
callers that need direct access to ServiceProvider, IdentityProvider,
HttpRequest, BindingContext, or protocol helper functions. New browser
SSO/SLO integrations should start with Saml, typed descriptors, and the
builder-backed config types shown above.
Use visible docs.rs modules, crate-root re-exports, and saml_rs::raw before
reaching for hidden lower-level module paths.
Features
[]
= ["crypto-bergshamra"]
= ["dep:bergshamra"]
With default-features = false, the protocol layer still builds messages,
parses metadata, and runs extraction. Operations that need signing,
verification, or encryption return SamlError::Unsupported.
The default crypto-bergshamra feature currently requires Rust 1.85 because
the bergshamra 0.6.3 dependency graph reaches kryptering 0.4.1 and
crypto-bigint 0.7.5, which declares Rust 1.85.
With crypto-bergshamra enabled:
- XML signatures can be verified against metadata-declared keys.
- Signed-reference placement checks help mitigate XML Signature Wrapping (XSW).
- XML-Enc support is available, but software RSA key-transport decryption is
gated off by default and requires an explicit compatibility opt-in through
XmlEncryptionPolicy.
Security
saml-rs is pre-1.0 and has not had an external security audit. Review the
crate, configuration, and peer metadata trust model before production use.
Security-sensitive defaults and checks include:
#![forbid(unsafe_code)]on the crate root.- DOCTYPE / XXE rejection and bounded XML parsing before authentication.
- XML escaping for generated templates, metadata endpoint locations, and SAML attribute values.
- Response validation for issuer, SAML status, assertion time window, audience,
destination/recipient, bearer subject confirmation, and
InResponseTo. - Logout validation for issuer and request/response correlation.
- Signed metadata verification with root coverage requirements.
- AuthnRequest root-signature coverage when signed requests are required.
- Detached Redirect/SimpleSign signatures bound to the fields consumed by the flow parser.
- HTTP-Redirect raw DEFLATE output limits.
- XML-Enc software RSA key-transport decryption disabled by default because the
bundled RustCrypto RSA backend, reached through
bergshamra/kryptering, is affected by RUSTSEC-2023-0071.
Schema validation is optional defense in depth via
context::set_schema_validator.
Development
RUSTDOCFLAGS="-D warnings -D missing_docs"
License
MIT.