0.6 to 0.7
This guide shows you how to upgrade saml-rs, opensaml, samlify, or
samlet from the latest 0.6.x release to 0.7.x.
If the code calls strict(), replace that call first. If Default, new,
try_new, or a config builder was enough, go to
Point constructors at the preset you need.
If the code starts typed Single Logout, go to Use NameID placeholders in a custom logout request template and the three sections after it.
If an identity provider has no NameID format configured, go to Expect no Format from an identity provider without a NameID format.
Replace strict()
Section titled “Replace strict()”This breaks code that calls SpValidationPolicy::strict,
IdpValidationPolicy::strict, or LogoutPolicy::strict.
Who must change: that code.
If the call needs no extra check, use Recommended:
let policy = SpValidationPolicy::recommended();If the service provider must still require a signature directly on the Assertion:
let require_assertion_signature = SpValidationPolicy { assertions: AssertionSignaturePolicy::RequireSigned, ..SpValidationPolicy::recommended()};If it must still require the RSA-SHA2 XML-DSig profile, and Assertion signatures can stay optional:
let require_rsa_sha2 = SpValidationPolicy { xml_signatures: XmlSignatureProfile::StrictRsaSha2, ..SpValidationPolicy::recommended()};If it must do both, set both fields. The two checks are independent. Why they stay separate is in Validation presets.
If the service provider must still sign AuthnRequests and reject a bearer
assertion that omits <AudienceRestriction>:
let sp = SpValidationPolicy { assertions: AssertionSignaturePolicy::RequireSigned, authn_requests: AuthnRequestSigningPolicy::Sign, audience: AudienceValidationPolicy::Validate, ..SpValidationPolicy::recommended()};If the identity provider must still reject an unsigned AuthnRequest:
let idp = IdpValidationPolicy { authn_requests: AuthnRequestValidationPolicy::RequireSigned, ..IdpValidationPolicy::recommended()};Replace LogoutPolicy::strict() with LogoutPolicy::recommended(). Both
require a signature on logout requests and responses.
Point constructors at the preset you need
Section titled “Point constructors at the preset you need”This breaks code that depended on Default, new, or try_new staying on
Compatibility, and code that depended on a config builder staying on the
removed bundle.
Who must change: that code.
SpValidationPolicy::default, IdpValidationPolicy::default,
LogoutPolicy::default, and SpConfig and IdpConfig new, try_new, and
builder are Recommended.
An identity provider on the builder default accepts an unsigned
AuthnRequest and can issue an assertion for it. A service provider on the
builder default accepts a bearer assertion that omits <AudienceRestriction>.
AuthnRequest signing and a direct Assertion signature are off as well.
If the service provider must keep those checks:
let sp = SpValidationPolicy { assertions: AssertionSignaturePolicy::RequireSigned, authn_requests: AuthnRequestSigningPolicy::Sign, audience: AudienceValidationPolicy::Validate, ..SpValidationPolicy::recommended()};If the identity provider must keep the unsigned-request rejection:
let idp = IdpValidationPolicy { authn_requests: AuthnRequestValidationPolicy::RequireSigned, ..IdpValidationPolicy::recommended()};To keep the legacy permissive preset on a builder:
let sp = SpConfig::builder(entity_id) .acs_endpoint(acs) .validation(SpValidationPolicy::compatibility()) .build()?;If try_new or builder().build() returns SamlError::Unsupported, the
build has no crypto provider. Recommended requires one: logout messages must
be signed, and a CBC-encrypted assertion requires a Response signature. Select
compatibility(), or another policy that does not require signatures, to
keep that build. new does not validate.
Leave field defaults and raw settings
Section titled “Leave field defaults and raw settings”Leave ResponseSignaturePolicy::default and
AuthnRequestValidationPolicy::default as they are. They are not the
Recommended preset. Raw settings defaults are unchanged.
SpValidationPolicy::compatibility, IdpValidationPolicy::compatibility,
and LogoutPolicy::compatibility stay available by name.
Use NameID placeholders in a custom logout request template
Section titled “Use NameID placeholders in a custom logout request template”Typed start_slo now sends the Format, NameQualifier, SPNameQualifier,
and SPProvidedID of the LogoutSubject NameId. It used to send the first
local name_id_format and no qualifiers.
This breaks a TemplatePolicy::logout_request_template whose NameID
attributes are not the ones sent for the subject. Session Authority
generation, and session participant generation with producer rules, fail with
SamlError::ProtocolProfile.
Who must change: code that sets that template.
Write the four attributes as placeholders:
<saml:NameID NameQualifier="{NameQualifier}" SPNameQualifier="{SPNameQualifier}" Format="{NameIDFormat}" SPProvidedID="{SPProvidedID}">{NameID}</saml:NameID>An attribute whose complete value is a placeholder is omitted when there is no value for it. Session participant generation without producer rules sends the template as written, so add the placeholders there too.
Set the format on a service provider logout subject
Section titled “Set the format on a service provider logout subject”This breaks logout at an identity provider that expects a specific NameID
Format, when the service provider builds the LogoutSubject with
NameId::new(value, None). start_slo now omits Format for that NameId.
Who must change: that service provider code. A subject from
SsoSession::logout_subject already carries the assertion’s format and
qualifiers.
Pass the format the session used:
let name_id = NameId::new(value, Some(NameIdFormat::EmailAddress));Pass identity provider logout the NameID the assertion carried
Section titled “Pass identity provider logout the NameID the assertion carried”This breaks session matching at a service provider, when the identity
provider passes start_slo a NameId whose format or qualifiers were not in
the assertion. start_slo now sends them as given.
Who must change: identity provider code that passes a NameId with a format
or qualifiers to start_slo, for example the requested subject of an
AuthnRequest.
Pass the format the NameId had in respond_sso or initiate_sso. Pass
qualifiers only when a custom login response template wrote them into the
assertion: respond_sso and initiate_sso write the NameID value and
Format only. A NameId without a format needs no change.
Expect qualifiers on the SSO session NameID
Section titled “Expect qualifiers on the SSO session NameID”This breaks an equality check between SsoSession::name_id() or
SsoSession::subject() and a NameId built by NameId::new. The session
NameId now holds the qualifiers of the assertion NameID.
Who must change: code that makes that comparison.
Compare NameId::value() and NameId::format() when only those matter.
Expect no Format from an identity provider without a NameID format
Section titled “Expect no Format from an identity provider without a NameID format”An identity provider with no configured NameID format used to write
Format="" on the NameID of an assertion and of a LogoutRequest, when the
NameId had no format. It now omits Format. Core §1.3.2 does not allow an
empty URI value, and Core §2.2.2 treats an omitted Format as
urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified.
This applies to typed respond_sso, initiate_sso, and start_slo, to raw
create_login_response and create_logout_request, and to a login response
template that writes Format="{NameIDFormat}". A raw service provider without
a NameID format omits Format in create_logout_request as well. An identity
provider with a configured format sends what it sent before.
This breaks code that reads the empty format back. For an assertion from such
an identity provider, SsoSession::name_id().format() is now None. It used
to be Some(NameIdFormat::Custom(String::new())).
Who must change: service provider code that compares that format, and a peer
that looks for the literal Format="".
Treat None as the unspecified format. To send a specific format, configure
it on the identity provider:
let config = IdpConfig::builder(entity_id) .name_id_format(NameIdFormat::EmailAddress);A LoginResponseOptions::custom callback fills the template itself and is
unchanged.