Skip to content

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.

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.

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 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.