Skip to main content

Saml

Struct Saml 

Source
pub struct Saml<Role = Unknown>(/* private fields */);
Expand description

Typed SAML facade for high-level browser SSO/SLO flows.

Implementations§

Source§

impl Saml<Idp>

Source

pub fn metadata_xml(&self) -> &str

Local IdP metadata XML.

Examples found in repository?
examples/sso.rs (line 59)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    use saml_rs::{
18        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
19        IdpDescriptor, IdpValidationPolicy, MetadataTrustPolicy, NameId, PrivateKeyPem,
20        RelayStateParam, ReplayPolicy, RespondSso, Saml, SamlValidationContext, SpConfig,
21        SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .credentials(credentials())
40            .validation(SpValidationPolicy::strict())
41            .build()?,
42    )?;
43    let idp = Saml::idp(
44        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
45            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
46            .credentials(credentials())
47            .validation(IdpValidationPolicy::strict())
48            .build()?,
49    )?;
50
51    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
52        EntityId::try_new("https://sp.example.com/metadata")?,
53        sp.metadata_xml(),
54        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
55        MetadataTrustPolicy::UnsignedForCompatibility,
56    )?;
57    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
58        EntityId::try_new("https://idp.example.com/metadata")?,
59        idp.metadata_xml(),
60        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
61        MetadataTrustPolicy::UnsignedForCompatibility,
62    )?;
63
64    let relay_state = RelayStateParam::try_from_option(Some("demo-state".to_string()))?;
65    let started = sp.start_sso(&idp_descriptor, StartSso::post().relay_state(relay_state))?;
66    println!(
67        "SP  -> AuthnRequest id = {}",
68        started.pending.request_id().as_str()
69    );
70
71    let request = idp.receive_sso(
72        &sp_descriptor,
73        BrowserInput::<AuthnRequest>::post(started.outbound.post_form()?.fields().to_vec()),
74        validation(),
75    )?;
76    println!(
77        "IdP <- request issuer  = {}",
78        request.message().issuer().as_str()
79    );
80
81    let response = idp.respond_sso(
82        &sp_descriptor,
83        &request,
84        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
85        RespondSso::post(),
86    )?;
87
88    let session = sp.finish_sso(
89        &idp_descriptor,
90        &started.pending,
91        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
92        validation(),
93    );
94    let session = session?;
95    println!("SP  <- authenticated   = {}", session.name_id().value());
96    Ok(())
97}
More examples
Hide additional examples
examples/slo.rs (line 60)
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16    use saml_rs::{
17        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
18        IdpDescriptor, IdpValidationPolicy, LogoutRequest, LogoutResponse, MetadataTrustPolicy,
19        NameId, PrivateKeyPem, ReplayPolicy, RespondSlo, RespondSso, Saml, SamlValidationContext,
20        SloEndpoint, SpConfig, SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse,
21        StartSlo, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .slo_endpoint(SloEndpoint::post("https://sp.example.com/slo")?)
40            .credentials(credentials())
41            .validation(SpValidationPolicy::strict())
42            .build()?,
43    )?;
44    let idp = Saml::idp(
45        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
46            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
47            .slo_endpoint(SloEndpoint::post("https://idp.example.com/slo")?)
48            .credentials(credentials())
49            .validation(IdpValidationPolicy::strict())
50            .build()?,
51    )?;
52    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
53        EntityId::try_new("https://sp.example.com/metadata")?,
54        sp.metadata_xml(),
55        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
56        MetadataTrustPolicy::UnsignedForCompatibility,
57    )?;
58    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
59        EntityId::try_new("https://idp.example.com/metadata")?,
60        idp.metadata_xml(),
61        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
62        MetadataTrustPolicy::UnsignedForCompatibility,
63    )?;
64
65    let sso = sp.start_sso(&idp_descriptor, StartSso::post())?;
66    let request = idp.receive_sso(
67        &sp_descriptor,
68        BrowserInput::<AuthnRequest>::post(sso.outbound.post_form()?.fields().to_vec()),
69        validation(),
70    )?;
71    let response = idp.respond_sso(
72        &sp_descriptor,
73        &request,
74        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
75        RespondSso::post(),
76    )?;
77    let session = sp.finish_sso(
78        &idp_descriptor,
79        &sso.pending,
80        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
81        validation(),
82    )?;
83
84    let subject = session
85        .logout_subject()
86        .ok_or("session has no logout subject")?;
87    let logout = sp.start_slo(&idp_descriptor, subject, StartSlo::post())?;
88    println!("SP  -> LogoutRequest id = {}", logout.pending.id().as_str());
89
90    let logout_request = idp.receive_slo(
91        &sp_descriptor,
92        BrowserInput::<LogoutRequest>::post(logout.outbound.post_form()?.fields().to_vec()),
93        validation(),
94    )?;
95    let logout_response = idp.respond_slo(
96        &sp_descriptor,
97        &logout_request,
98        RespondSlo::post().relay_state(logout.pending.relay_state().clone()),
99    )?;
100    let completed = sp.finish_slo(
101        &idp_descriptor,
102        &logout.pending,
103        BrowserInput::<LogoutResponse>::post(logout_response.post_form()?.fields().to_vec()),
104        validation(),
105    )?;
106    println!(
107        "SP  <- LogoutResponse status = {}",
108        completed.status().unwrap_or("missing")
109    );
110    Ok(())
111}
Source

pub fn raw_identity_provider(&self) -> &IdentityProvider

Raw compatibility Identity Provider.

Source

pub fn receive_sso( &self, sp: &SpDescriptor, input: BrowserInput<AuthnRequest>, validation: SamlValidationContext<'_>, ) -> Result<Received<AuthnRequest>, SamlError>

Receive an SP AuthnRequest.

§Errors

Returns SamlError when browser input or relay state is invalid, the request binding is unsupported, SP metadata cannot be parsed, XML parsing or signature/trust validation fails, the request destination does not match local metadata, an enabled crate::AuthnRequestAgePolicy rejects IssueInstant, or replay validation detects a duplicate or expired request.

§Examples
use saml_rs::{
    AuthnRequest, BrowserInput, FormField, ReplayPolicy, RespondSso, Saml,
    SamlValidationContext, SpDescriptor, Subject,
};
use std::time::SystemTime;

let validation = SamlValidationContext::new(
    SystemTime::now(),
    ReplayPolicy::DisabledForCompatibility,
);
let input = BrowserInput::<AuthnRequest>::post(fields);
let request = idp.receive_sso(sp, input, validation)?;
let response = idp.respond_sso(sp, &request, subject, RespondSso::post())?;

let form = response.post_form()?;
Examples found in repository?
examples/sso.rs (lines 71-75)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    use saml_rs::{
18        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
19        IdpDescriptor, IdpValidationPolicy, MetadataTrustPolicy, NameId, PrivateKeyPem,
20        RelayStateParam, ReplayPolicy, RespondSso, Saml, SamlValidationContext, SpConfig,
21        SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .credentials(credentials())
40            .validation(SpValidationPolicy::strict())
41            .build()?,
42    )?;
43    let idp = Saml::idp(
44        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
45            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
46            .credentials(credentials())
47            .validation(IdpValidationPolicy::strict())
48            .build()?,
49    )?;
50
51    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
52        EntityId::try_new("https://sp.example.com/metadata")?,
53        sp.metadata_xml(),
54        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
55        MetadataTrustPolicy::UnsignedForCompatibility,
56    )?;
57    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
58        EntityId::try_new("https://idp.example.com/metadata")?,
59        idp.metadata_xml(),
60        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
61        MetadataTrustPolicy::UnsignedForCompatibility,
62    )?;
63
64    let relay_state = RelayStateParam::try_from_option(Some("demo-state".to_string()))?;
65    let started = sp.start_sso(&idp_descriptor, StartSso::post().relay_state(relay_state))?;
66    println!(
67        "SP  -> AuthnRequest id = {}",
68        started.pending.request_id().as_str()
69    );
70
71    let request = idp.receive_sso(
72        &sp_descriptor,
73        BrowserInput::<AuthnRequest>::post(started.outbound.post_form()?.fields().to_vec()),
74        validation(),
75    )?;
76    println!(
77        "IdP <- request issuer  = {}",
78        request.message().issuer().as_str()
79    );
80
81    let response = idp.respond_sso(
82        &sp_descriptor,
83        &request,
84        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
85        RespondSso::post(),
86    )?;
87
88    let session = sp.finish_sso(
89        &idp_descriptor,
90        &started.pending,
91        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
92        validation(),
93    );
94    let session = session?;
95    println!("SP  <- authenticated   = {}", session.name_id().value());
96    Ok(())
97}
More examples
Hide additional examples
examples/slo.rs (lines 66-70)
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16    use saml_rs::{
17        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
18        IdpDescriptor, IdpValidationPolicy, LogoutRequest, LogoutResponse, MetadataTrustPolicy,
19        NameId, PrivateKeyPem, ReplayPolicy, RespondSlo, RespondSso, Saml, SamlValidationContext,
20        SloEndpoint, SpConfig, SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse,
21        StartSlo, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .slo_endpoint(SloEndpoint::post("https://sp.example.com/slo")?)
40            .credentials(credentials())
41            .validation(SpValidationPolicy::strict())
42            .build()?,
43    )?;
44    let idp = Saml::idp(
45        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
46            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
47            .slo_endpoint(SloEndpoint::post("https://idp.example.com/slo")?)
48            .credentials(credentials())
49            .validation(IdpValidationPolicy::strict())
50            .build()?,
51    )?;
52    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
53        EntityId::try_new("https://sp.example.com/metadata")?,
54        sp.metadata_xml(),
55        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
56        MetadataTrustPolicy::UnsignedForCompatibility,
57    )?;
58    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
59        EntityId::try_new("https://idp.example.com/metadata")?,
60        idp.metadata_xml(),
61        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
62        MetadataTrustPolicy::UnsignedForCompatibility,
63    )?;
64
65    let sso = sp.start_sso(&idp_descriptor, StartSso::post())?;
66    let request = idp.receive_sso(
67        &sp_descriptor,
68        BrowserInput::<AuthnRequest>::post(sso.outbound.post_form()?.fields().to_vec()),
69        validation(),
70    )?;
71    let response = idp.respond_sso(
72        &sp_descriptor,
73        &request,
74        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
75        RespondSso::post(),
76    )?;
77    let session = sp.finish_sso(
78        &idp_descriptor,
79        &sso.pending,
80        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
81        validation(),
82    )?;
83
84    let subject = session
85        .logout_subject()
86        .ok_or("session has no logout subject")?;
87    let logout = sp.start_slo(&idp_descriptor, subject, StartSlo::post())?;
88    println!("SP  -> LogoutRequest id = {}", logout.pending.id().as_str());
89
90    let logout_request = idp.receive_slo(
91        &sp_descriptor,
92        BrowserInput::<LogoutRequest>::post(logout.outbound.post_form()?.fields().to_vec()),
93        validation(),
94    )?;
95    let logout_response = idp.respond_slo(
96        &sp_descriptor,
97        &logout_request,
98        RespondSlo::post().relay_state(logout.pending.relay_state().clone()),
99    )?;
100    let completed = sp.finish_slo(
101        &idp_descriptor,
102        &logout.pending,
103        BrowserInput::<LogoutResponse>::post(logout_response.post_form()?.fields().to_vec()),
104        validation(),
105    )?;
106    println!(
107        "SP  <- LogoutResponse status = {}",
108        completed.status().unwrap_or("missing")
109    );
110    Ok(())
111}
Source

pub fn respond_sso( &self, sp: &SpDescriptor, request: &Received<AuthnRequest>, subject: Subject, options: RespondSso, ) -> Result<Outbound<SsoResponse>, SamlError>

Respond to a received SP AuthnRequest.

§Errors

Returns SamlError when the request issuer does not match the SP descriptor, relay state is invalid, the request ACS selection conflicts with the response binding or SP metadata, required metadata or signing keys are missing, the configured issuance expiration overflows the supported timestamp range, producer rules are combined with a custom login response template, an error status is combined with a login response template, or response creation fails.

Examples found in repository?
examples/sso.rs (lines 81-86)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    use saml_rs::{
18        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
19        IdpDescriptor, IdpValidationPolicy, MetadataTrustPolicy, NameId, PrivateKeyPem,
20        RelayStateParam, ReplayPolicy, RespondSso, Saml, SamlValidationContext, SpConfig,
21        SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .credentials(credentials())
40            .validation(SpValidationPolicy::strict())
41            .build()?,
42    )?;
43    let idp = Saml::idp(
44        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
45            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
46            .credentials(credentials())
47            .validation(IdpValidationPolicy::strict())
48            .build()?,
49    )?;
50
51    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
52        EntityId::try_new("https://sp.example.com/metadata")?,
53        sp.metadata_xml(),
54        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
55        MetadataTrustPolicy::UnsignedForCompatibility,
56    )?;
57    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
58        EntityId::try_new("https://idp.example.com/metadata")?,
59        idp.metadata_xml(),
60        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
61        MetadataTrustPolicy::UnsignedForCompatibility,
62    )?;
63
64    let relay_state = RelayStateParam::try_from_option(Some("demo-state".to_string()))?;
65    let started = sp.start_sso(&idp_descriptor, StartSso::post().relay_state(relay_state))?;
66    println!(
67        "SP  -> AuthnRequest id = {}",
68        started.pending.request_id().as_str()
69    );
70
71    let request = idp.receive_sso(
72        &sp_descriptor,
73        BrowserInput::<AuthnRequest>::post(started.outbound.post_form()?.fields().to_vec()),
74        validation(),
75    )?;
76    println!(
77        "IdP <- request issuer  = {}",
78        request.message().issuer().as_str()
79    );
80
81    let response = idp.respond_sso(
82        &sp_descriptor,
83        &request,
84        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
85        RespondSso::post(),
86    )?;
87
88    let session = sp.finish_sso(
89        &idp_descriptor,
90        &started.pending,
91        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
92        validation(),
93    );
94    let session = session?;
95    println!("SP  <- authenticated   = {}", session.name_id().value());
96    Ok(())
97}
More examples
Hide additional examples
examples/slo.rs (lines 71-76)
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16    use saml_rs::{
17        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
18        IdpDescriptor, IdpValidationPolicy, LogoutRequest, LogoutResponse, MetadataTrustPolicy,
19        NameId, PrivateKeyPem, ReplayPolicy, RespondSlo, RespondSso, Saml, SamlValidationContext,
20        SloEndpoint, SpConfig, SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse,
21        StartSlo, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .slo_endpoint(SloEndpoint::post("https://sp.example.com/slo")?)
40            .credentials(credentials())
41            .validation(SpValidationPolicy::strict())
42            .build()?,
43    )?;
44    let idp = Saml::idp(
45        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
46            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
47            .slo_endpoint(SloEndpoint::post("https://idp.example.com/slo")?)
48            .credentials(credentials())
49            .validation(IdpValidationPolicy::strict())
50            .build()?,
51    )?;
52    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
53        EntityId::try_new("https://sp.example.com/metadata")?,
54        sp.metadata_xml(),
55        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
56        MetadataTrustPolicy::UnsignedForCompatibility,
57    )?;
58    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
59        EntityId::try_new("https://idp.example.com/metadata")?,
60        idp.metadata_xml(),
61        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
62        MetadataTrustPolicy::UnsignedForCompatibility,
63    )?;
64
65    let sso = sp.start_sso(&idp_descriptor, StartSso::post())?;
66    let request = idp.receive_sso(
67        &sp_descriptor,
68        BrowserInput::<AuthnRequest>::post(sso.outbound.post_form()?.fields().to_vec()),
69        validation(),
70    )?;
71    let response = idp.respond_sso(
72        &sp_descriptor,
73        &request,
74        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
75        RespondSso::post(),
76    )?;
77    let session = sp.finish_sso(
78        &idp_descriptor,
79        &sso.pending,
80        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
81        validation(),
82    )?;
83
84    let subject = session
85        .logout_subject()
86        .ok_or("session has no logout subject")?;
87    let logout = sp.start_slo(&idp_descriptor, subject, StartSlo::post())?;
88    println!("SP  -> LogoutRequest id = {}", logout.pending.id().as_str());
89
90    let logout_request = idp.receive_slo(
91        &sp_descriptor,
92        BrowserInput::<LogoutRequest>::post(logout.outbound.post_form()?.fields().to_vec()),
93        validation(),
94    )?;
95    let logout_response = idp.respond_slo(
96        &sp_descriptor,
97        &logout_request,
98        RespondSlo::post().relay_state(logout.pending.relay_state().clone()),
99    )?;
100    let completed = sp.finish_slo(
101        &idp_descriptor,
102        &logout.pending,
103        BrowserInput::<LogoutResponse>::post(logout_response.post_form()?.fields().to_vec()),
104        validation(),
105    )?;
106    println!(
107        "SP  <- LogoutResponse status = {}",
108        completed.status().unwrap_or("missing")
109    );
110    Ok(())
111}
Source

pub fn initiate_sso( &self, sp: &SpDescriptor, subject: Subject, options: RespondSso, ) -> Result<Outbound<SsoResponse>, SamlError>

Initiate IdP-initiated SSO.

§Errors

Returns SamlError when relay state is invalid, SP metadata cannot be parsed, a compatible ACS endpoint or signing key is missing, the selected binding is unsupported, the configured issuance expiration overflows the supported timestamp range, producer rules are combined with a custom login response template, an error status is combined with a login response template, or response creation fails.

§Examples
use saml_rs::{
    BrowserInput, FormField, IdpDescriptor, ReplayPolicy, RespondSso, Saml,
    SamlValidationContext, SpDescriptor, SsoResponse, Subject,
};
use std::time::SystemTime;

let response = idp.initiate_sso(sp_descriptor, subject, RespondSso::post())?;
let form = response.post_form()?;

let validation = SamlValidationContext::new(
    SystemTime::now(),
    ReplayPolicy::DisabledForCompatibility,
);
let session = sp.accept_unsolicited_sso(
    idp_descriptor,
    BrowserInput::<SsoResponse>::post(form_fields),
    validation,
)?;
let issuer = session.issuer().as_str();
Source§

impl Saml<Sp>

Source

pub fn start_slo( &self, idp: &IdpDescriptor, subject: LogoutSubject, options: StartSlo, ) -> Result<Started<LogoutRequest>, SamlError>

Start SP-initiated Single Logout.

§Errors

Returns SamlError when relay state is invalid, IdP metadata cannot be parsed, a compatible logout endpoint or signing key is missing, the selected binding is unsupported, or logout request creation fails. StartSlo::apply_single_logout_generation_rules also rejects a missing SessionIndex, an http peer endpoint unless StartSlo::allow_http_single_logout is selected, and rejects the samlify-port LogoutSigning::DoNotSignForCompatibility.

§Examples
use saml_rs::{IdpDescriptor, LogoutSubject, Saml, StartSlo};

let started = sp.start_slo(idp, subject, StartSlo::post())?;
let form = started.outbound.post_form()?;
let snapshot = started.pending.snapshot();
Examples found in repository?
examples/slo.rs (line 87)
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16    use saml_rs::{
17        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
18        IdpDescriptor, IdpValidationPolicy, LogoutRequest, LogoutResponse, MetadataTrustPolicy,
19        NameId, PrivateKeyPem, ReplayPolicy, RespondSlo, RespondSso, Saml, SamlValidationContext,
20        SloEndpoint, SpConfig, SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse,
21        StartSlo, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .slo_endpoint(SloEndpoint::post("https://sp.example.com/slo")?)
40            .credentials(credentials())
41            .validation(SpValidationPolicy::strict())
42            .build()?,
43    )?;
44    let idp = Saml::idp(
45        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
46            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
47            .slo_endpoint(SloEndpoint::post("https://idp.example.com/slo")?)
48            .credentials(credentials())
49            .validation(IdpValidationPolicy::strict())
50            .build()?,
51    )?;
52    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
53        EntityId::try_new("https://sp.example.com/metadata")?,
54        sp.metadata_xml(),
55        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
56        MetadataTrustPolicy::UnsignedForCompatibility,
57    )?;
58    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
59        EntityId::try_new("https://idp.example.com/metadata")?,
60        idp.metadata_xml(),
61        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
62        MetadataTrustPolicy::UnsignedForCompatibility,
63    )?;
64
65    let sso = sp.start_sso(&idp_descriptor, StartSso::post())?;
66    let request = idp.receive_sso(
67        &sp_descriptor,
68        BrowserInput::<AuthnRequest>::post(sso.outbound.post_form()?.fields().to_vec()),
69        validation(),
70    )?;
71    let response = idp.respond_sso(
72        &sp_descriptor,
73        &request,
74        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
75        RespondSso::post(),
76    )?;
77    let session = sp.finish_sso(
78        &idp_descriptor,
79        &sso.pending,
80        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
81        validation(),
82    )?;
83
84    let subject = session
85        .logout_subject()
86        .ok_or("session has no logout subject")?;
87    let logout = sp.start_slo(&idp_descriptor, subject, StartSlo::post())?;
88    println!("SP  -> LogoutRequest id = {}", logout.pending.id().as_str());
89
90    let logout_request = idp.receive_slo(
91        &sp_descriptor,
92        BrowserInput::<LogoutRequest>::post(logout.outbound.post_form()?.fields().to_vec()),
93        validation(),
94    )?;
95    let logout_response = idp.respond_slo(
96        &sp_descriptor,
97        &logout_request,
98        RespondSlo::post().relay_state(logout.pending.relay_state().clone()),
99    )?;
100    let completed = sp.finish_slo(
101        &idp_descriptor,
102        &logout.pending,
103        BrowserInput::<LogoutResponse>::post(logout_response.post_form()?.fields().to_vec()),
104        validation(),
105    )?;
106    println!(
107        "SP  <- LogoutResponse status = {}",
108        completed.status().unwrap_or("missing")
109    );
110    Ok(())
111}
Source

pub fn receive_slo( &self, idp: &IdpDescriptor, input: BrowserInput<LogoutRequest>, validation: SamlValidationContext<'_>, ) -> Result<Received<LogoutRequest>, SamlError>

Receive an IdP LogoutRequest.

§Errors

Returns SamlError when the browser input or relay state is invalid, the binding is unsupported for logout, IdP metadata cannot be parsed, XML parsing or signature/trust validation fails, required IssueInstant or optional NotOnOrAfter is not conformant, NotOnOrAfter has expired under saml-rs’ fail-closed policy, the destination does not match local metadata, or replay validation detects a duplicate or unusable expiration.

Source

pub fn respond_slo( &self, idp: &IdpDescriptor, request: &Received<LogoutRequest>, options: RespondSlo, ) -> Result<Outbound<LogoutResponse>, SamlError>

Respond to a received IdP LogoutRequest.

§Errors

Returns SamlError when IdP metadata cannot be parsed, relay state is invalid, a compatible logout endpoint or signing key is missing, the selected binding is unsupported, or logout response creation fails. RespondSlo::apply_single_logout_generation_rules also rejects an http peer endpoint unless RespondSlo::allow_http_single_logout is selected.

Source

pub fn finish_slo( &self, idp: &IdpDescriptor, pending: &PendingLogoutRequest, input: BrowserInput<LogoutResponse>, validation: SamlValidationContext<'_>, ) -> Result<LogoutCompleted, SamlError>

Finish SP-initiated Single Logout using stored pending LogoutRequest state.

§Errors

Returns SamlError when the response does not match the pending request, including issuer, binding, relay state, destination, or InResponseTo mismatches; when IdP metadata cannot be parsed; when XML, signature, trust, status, or time validation fails; or when replay validation detects a duplicate or expired message. Response signatures follow crate::LogoutPolicy::responses. The Single Logout accept combination sets that field to crate::LogoutSignaturePolicy::RequireSigned.

§Examples
use saml_rs::{
    BrowserInput, FormField, IdpDescriptor, LogoutResponse, PendingLogoutRequest,
    ReplayPolicy, Saml, SamlValidationContext,
};
use std::time::SystemTime;

let validation = SamlValidationContext::new(
    SystemTime::now(),
    ReplayPolicy::DisabledForCompatibility,
);
let completed = sp.finish_slo(
    idp,
    pending,
    BrowserInput::<LogoutResponse>::post(fields),
    validation,
)?;

let peer = completed.peer_entity_id().as_str();
Examples found in repository?
examples/slo.rs (lines 100-105)
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16    use saml_rs::{
17        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
18        IdpDescriptor, IdpValidationPolicy, LogoutRequest, LogoutResponse, MetadataTrustPolicy,
19        NameId, PrivateKeyPem, ReplayPolicy, RespondSlo, RespondSso, Saml, SamlValidationContext,
20        SloEndpoint, SpConfig, SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse,
21        StartSlo, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .slo_endpoint(SloEndpoint::post("https://sp.example.com/slo")?)
40            .credentials(credentials())
41            .validation(SpValidationPolicy::strict())
42            .build()?,
43    )?;
44    let idp = Saml::idp(
45        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
46            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
47            .slo_endpoint(SloEndpoint::post("https://idp.example.com/slo")?)
48            .credentials(credentials())
49            .validation(IdpValidationPolicy::strict())
50            .build()?,
51    )?;
52    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
53        EntityId::try_new("https://sp.example.com/metadata")?,
54        sp.metadata_xml(),
55        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
56        MetadataTrustPolicy::UnsignedForCompatibility,
57    )?;
58    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
59        EntityId::try_new("https://idp.example.com/metadata")?,
60        idp.metadata_xml(),
61        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
62        MetadataTrustPolicy::UnsignedForCompatibility,
63    )?;
64
65    let sso = sp.start_sso(&idp_descriptor, StartSso::post())?;
66    let request = idp.receive_sso(
67        &sp_descriptor,
68        BrowserInput::<AuthnRequest>::post(sso.outbound.post_form()?.fields().to_vec()),
69        validation(),
70    )?;
71    let response = idp.respond_sso(
72        &sp_descriptor,
73        &request,
74        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
75        RespondSso::post(),
76    )?;
77    let session = sp.finish_sso(
78        &idp_descriptor,
79        &sso.pending,
80        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
81        validation(),
82    )?;
83
84    let subject = session
85        .logout_subject()
86        .ok_or("session has no logout subject")?;
87    let logout = sp.start_slo(&idp_descriptor, subject, StartSlo::post())?;
88    println!("SP  -> LogoutRequest id = {}", logout.pending.id().as_str());
89
90    let logout_request = idp.receive_slo(
91        &sp_descriptor,
92        BrowserInput::<LogoutRequest>::post(logout.outbound.post_form()?.fields().to_vec()),
93        validation(),
94    )?;
95    let logout_response = idp.respond_slo(
96        &sp_descriptor,
97        &logout_request,
98        RespondSlo::post().relay_state(logout.pending.relay_state().clone()),
99    )?;
100    let completed = sp.finish_slo(
101        &idp_descriptor,
102        &logout.pending,
103        BrowserInput::<LogoutResponse>::post(logout_response.post_form()?.fields().to_vec()),
104        validation(),
105    )?;
106    println!(
107        "SP  <- LogoutResponse status = {}",
108        completed.status().unwrap_or("missing")
109    );
110    Ok(())
111}
Source§

impl Saml<Idp>

Source

pub fn start_slo( &self, sp: &SpDescriptor, subject: LogoutSubject, options: StartSlo, ) -> Result<Started<LogoutRequest>, SamlError>

Start Session Authority Single Logout.

The generated LogoutRequest always carries a UTC NotOnOrAfter derived from the configured crate::IdpConfig::issuance_lifetime and the same captured IssueInstant. That attribute cannot be omitted. StartSlo::apply_single_logout_generation_rules signs the request and still allows SessionIndex to be omitted. It does not require an https peer endpoint.

§Errors

Returns SamlError when relay state is invalid, SP metadata cannot be parsed, a compatible logout endpoint or signing key is missing, the selected binding is unsupported, logout request creation fails, or the configured issuance lifetime cannot be added to the current issue instant. StartSlo::apply_single_logout_generation_rules also rejects LogoutSigning::DoNotSignForCompatibility.

§Examples
use saml_rs::{LogoutSubject, Saml, SpDescriptor, StartSlo};

let started = idp.start_slo(sp, subject, StartSlo::post())?;
let form = started.outbound.post_form()?;
let snapshot = started.pending.snapshot();
Source

pub fn receive_slo( &self, sp: &SpDescriptor, input: BrowserInput<LogoutRequest>, validation: SamlValidationContext<'_>, ) -> Result<Received<LogoutRequest>, SamlError>

Receive an SP LogoutRequest.

§Errors

Returns SamlError when the browser input or relay state is invalid, the binding is unsupported for logout, SP metadata cannot be parsed, XML parsing or signature/trust validation fails, required IssueInstant or optional NotOnOrAfter is not conformant, NotOnOrAfter has expired under saml-rs’ fail-closed policy, the destination does not match local metadata, or replay validation detects a duplicate or unusable expiration.

§Examples
use saml_rs::{
    BrowserInput, FormField, LogoutRequest, ReplayPolicy, RespondSlo, Saml,
    SamlValidationContext, SpDescriptor,
};
use std::time::SystemTime;

let validation = SamlValidationContext::new(
    SystemTime::now(),
    ReplayPolicy::DisabledForCompatibility,
);
let input = BrowserInput::<LogoutRequest>::post(fields);
let request = idp.receive_slo(sp, input, validation)?;
let response = idp.respond_slo(sp, &request, RespondSlo::post())?;

let form = response.post_form()?;
Examples found in repository?
examples/slo.rs (lines 90-94)
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16    use saml_rs::{
17        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
18        IdpDescriptor, IdpValidationPolicy, LogoutRequest, LogoutResponse, MetadataTrustPolicy,
19        NameId, PrivateKeyPem, ReplayPolicy, RespondSlo, RespondSso, Saml, SamlValidationContext,
20        SloEndpoint, SpConfig, SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse,
21        StartSlo, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .slo_endpoint(SloEndpoint::post("https://sp.example.com/slo")?)
40            .credentials(credentials())
41            .validation(SpValidationPolicy::strict())
42            .build()?,
43    )?;
44    let idp = Saml::idp(
45        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
46            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
47            .slo_endpoint(SloEndpoint::post("https://idp.example.com/slo")?)
48            .credentials(credentials())
49            .validation(IdpValidationPolicy::strict())
50            .build()?,
51    )?;
52    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
53        EntityId::try_new("https://sp.example.com/metadata")?,
54        sp.metadata_xml(),
55        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
56        MetadataTrustPolicy::UnsignedForCompatibility,
57    )?;
58    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
59        EntityId::try_new("https://idp.example.com/metadata")?,
60        idp.metadata_xml(),
61        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
62        MetadataTrustPolicy::UnsignedForCompatibility,
63    )?;
64
65    let sso = sp.start_sso(&idp_descriptor, StartSso::post())?;
66    let request = idp.receive_sso(
67        &sp_descriptor,
68        BrowserInput::<AuthnRequest>::post(sso.outbound.post_form()?.fields().to_vec()),
69        validation(),
70    )?;
71    let response = idp.respond_sso(
72        &sp_descriptor,
73        &request,
74        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
75        RespondSso::post(),
76    )?;
77    let session = sp.finish_sso(
78        &idp_descriptor,
79        &sso.pending,
80        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
81        validation(),
82    )?;
83
84    let subject = session
85        .logout_subject()
86        .ok_or("session has no logout subject")?;
87    let logout = sp.start_slo(&idp_descriptor, subject, StartSlo::post())?;
88    println!("SP  -> LogoutRequest id = {}", logout.pending.id().as_str());
89
90    let logout_request = idp.receive_slo(
91        &sp_descriptor,
92        BrowserInput::<LogoutRequest>::post(logout.outbound.post_form()?.fields().to_vec()),
93        validation(),
94    )?;
95    let logout_response = idp.respond_slo(
96        &sp_descriptor,
97        &logout_request,
98        RespondSlo::post().relay_state(logout.pending.relay_state().clone()),
99    )?;
100    let completed = sp.finish_slo(
101        &idp_descriptor,
102        &logout.pending,
103        BrowserInput::<LogoutResponse>::post(logout_response.post_form()?.fields().to_vec()),
104        validation(),
105    )?;
106    println!(
107        "SP  <- LogoutResponse status = {}",
108        completed.status().unwrap_or("missing")
109    );
110    Ok(())
111}
Source

pub fn respond_slo( &self, sp: &SpDescriptor, request: &Received<LogoutRequest>, options: RespondSlo, ) -> Result<Outbound<LogoutResponse>, SamlError>

Respond to a received SP LogoutRequest.

§Errors

Returns SamlError when SP metadata cannot be parsed, relay state is invalid, a compatible logout endpoint or signing key is missing, the selected binding is unsupported, or logout response creation fails. RespondSlo::apply_single_logout_generation_rules does not add an https requirement for this role.

§Examples
use saml_rs::{LogoutRequest, Received, RespondSlo, Saml, SpDescriptor};

let response = idp.respond_slo(sp, request, RespondSlo::post())?;
let form = response.post_form()?;
Examples found in repository?
examples/slo.rs (lines 95-99)
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16    use saml_rs::{
17        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
18        IdpDescriptor, IdpValidationPolicy, LogoutRequest, LogoutResponse, MetadataTrustPolicy,
19        NameId, PrivateKeyPem, ReplayPolicy, RespondSlo, RespondSso, Saml, SamlValidationContext,
20        SloEndpoint, SpConfig, SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse,
21        StartSlo, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .slo_endpoint(SloEndpoint::post("https://sp.example.com/slo")?)
40            .credentials(credentials())
41            .validation(SpValidationPolicy::strict())
42            .build()?,
43    )?;
44    let idp = Saml::idp(
45        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
46            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
47            .slo_endpoint(SloEndpoint::post("https://idp.example.com/slo")?)
48            .credentials(credentials())
49            .validation(IdpValidationPolicy::strict())
50            .build()?,
51    )?;
52    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
53        EntityId::try_new("https://sp.example.com/metadata")?,
54        sp.metadata_xml(),
55        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
56        MetadataTrustPolicy::UnsignedForCompatibility,
57    )?;
58    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
59        EntityId::try_new("https://idp.example.com/metadata")?,
60        idp.metadata_xml(),
61        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
62        MetadataTrustPolicy::UnsignedForCompatibility,
63    )?;
64
65    let sso = sp.start_sso(&idp_descriptor, StartSso::post())?;
66    let request = idp.receive_sso(
67        &sp_descriptor,
68        BrowserInput::<AuthnRequest>::post(sso.outbound.post_form()?.fields().to_vec()),
69        validation(),
70    )?;
71    let response = idp.respond_sso(
72        &sp_descriptor,
73        &request,
74        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
75        RespondSso::post(),
76    )?;
77    let session = sp.finish_sso(
78        &idp_descriptor,
79        &sso.pending,
80        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
81        validation(),
82    )?;
83
84    let subject = session
85        .logout_subject()
86        .ok_or("session has no logout subject")?;
87    let logout = sp.start_slo(&idp_descriptor, subject, StartSlo::post())?;
88    println!("SP  -> LogoutRequest id = {}", logout.pending.id().as_str());
89
90    let logout_request = idp.receive_slo(
91        &sp_descriptor,
92        BrowserInput::<LogoutRequest>::post(logout.outbound.post_form()?.fields().to_vec()),
93        validation(),
94    )?;
95    let logout_response = idp.respond_slo(
96        &sp_descriptor,
97        &logout_request,
98        RespondSlo::post().relay_state(logout.pending.relay_state().clone()),
99    )?;
100    let completed = sp.finish_slo(
101        &idp_descriptor,
102        &logout.pending,
103        BrowserInput::<LogoutResponse>::post(logout_response.post_form()?.fields().to_vec()),
104        validation(),
105    )?;
106    println!(
107        "SP  <- LogoutResponse status = {}",
108        completed.status().unwrap_or("missing")
109    );
110    Ok(())
111}
Source

pub fn finish_slo( &self, sp: &SpDescriptor, pending: &PendingLogoutRequest, input: BrowserInput<LogoutResponse>, validation: SamlValidationContext<'_>, ) -> Result<LogoutCompleted, SamlError>

Finish IdP-initiated Single Logout using stored pending LogoutRequest state.

§Errors

Returns SamlError when the response does not match the pending request, including issuer, binding, relay state, destination, or InResponseTo mismatches; when SP metadata cannot be parsed; when XML, signature, trust, status, or time validation fails; or when replay validation detects a duplicate or expired message. Response signatures follow crate::LogoutPolicy::responses. The Single Logout accept combination sets that field to crate::LogoutSignaturePolicy::RequireSigned.

§Examples
use saml_rs::{
    BrowserInput, FormField, LogoutResponse, PendingLogoutRequest, ReplayPolicy,
    Saml, SamlValidationContext, SpDescriptor,
};
use std::time::SystemTime;

let validation = SamlValidationContext::new(
    SystemTime::now(),
    ReplayPolicy::DisabledForCompatibility,
);
let completed = idp.finish_slo(
    sp,
    pending,
    BrowserInput::<LogoutResponse>::post(fields),
    validation,
)?;

let peer = completed.peer_entity_id().as_str();
Source§

impl Saml<Sp>

Source

pub fn metadata_xml(&self) -> &str

Local SP metadata XML.

Examples found in repository?
examples/sso.rs (line 53)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    use saml_rs::{
18        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
19        IdpDescriptor, IdpValidationPolicy, MetadataTrustPolicy, NameId, PrivateKeyPem,
20        RelayStateParam, ReplayPolicy, RespondSso, Saml, SamlValidationContext, SpConfig,
21        SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .credentials(credentials())
40            .validation(SpValidationPolicy::strict())
41            .build()?,
42    )?;
43    let idp = Saml::idp(
44        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
45            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
46            .credentials(credentials())
47            .validation(IdpValidationPolicy::strict())
48            .build()?,
49    )?;
50
51    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
52        EntityId::try_new("https://sp.example.com/metadata")?,
53        sp.metadata_xml(),
54        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
55        MetadataTrustPolicy::UnsignedForCompatibility,
56    )?;
57    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
58        EntityId::try_new("https://idp.example.com/metadata")?,
59        idp.metadata_xml(),
60        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
61        MetadataTrustPolicy::UnsignedForCompatibility,
62    )?;
63
64    let relay_state = RelayStateParam::try_from_option(Some("demo-state".to_string()))?;
65    let started = sp.start_sso(&idp_descriptor, StartSso::post().relay_state(relay_state))?;
66    println!(
67        "SP  -> AuthnRequest id = {}",
68        started.pending.request_id().as_str()
69    );
70
71    let request = idp.receive_sso(
72        &sp_descriptor,
73        BrowserInput::<AuthnRequest>::post(started.outbound.post_form()?.fields().to_vec()),
74        validation(),
75    )?;
76    println!(
77        "IdP <- request issuer  = {}",
78        request.message().issuer().as_str()
79    );
80
81    let response = idp.respond_sso(
82        &sp_descriptor,
83        &request,
84        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
85        RespondSso::post(),
86    )?;
87
88    let session = sp.finish_sso(
89        &idp_descriptor,
90        &started.pending,
91        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
92        validation(),
93    );
94    let session = session?;
95    println!("SP  <- authenticated   = {}", session.name_id().value());
96    Ok(())
97}
More examples
Hide additional examples
examples/slo.rs (line 54)
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16    use saml_rs::{
17        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
18        IdpDescriptor, IdpValidationPolicy, LogoutRequest, LogoutResponse, MetadataTrustPolicy,
19        NameId, PrivateKeyPem, ReplayPolicy, RespondSlo, RespondSso, Saml, SamlValidationContext,
20        SloEndpoint, SpConfig, SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse,
21        StartSlo, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .slo_endpoint(SloEndpoint::post("https://sp.example.com/slo")?)
40            .credentials(credentials())
41            .validation(SpValidationPolicy::strict())
42            .build()?,
43    )?;
44    let idp = Saml::idp(
45        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
46            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
47            .slo_endpoint(SloEndpoint::post("https://idp.example.com/slo")?)
48            .credentials(credentials())
49            .validation(IdpValidationPolicy::strict())
50            .build()?,
51    )?;
52    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
53        EntityId::try_new("https://sp.example.com/metadata")?,
54        sp.metadata_xml(),
55        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
56        MetadataTrustPolicy::UnsignedForCompatibility,
57    )?;
58    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
59        EntityId::try_new("https://idp.example.com/metadata")?,
60        idp.metadata_xml(),
61        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
62        MetadataTrustPolicy::UnsignedForCompatibility,
63    )?;
64
65    let sso = sp.start_sso(&idp_descriptor, StartSso::post())?;
66    let request = idp.receive_sso(
67        &sp_descriptor,
68        BrowserInput::<AuthnRequest>::post(sso.outbound.post_form()?.fields().to_vec()),
69        validation(),
70    )?;
71    let response = idp.respond_sso(
72        &sp_descriptor,
73        &request,
74        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
75        RespondSso::post(),
76    )?;
77    let session = sp.finish_sso(
78        &idp_descriptor,
79        &sso.pending,
80        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
81        validation(),
82    )?;
83
84    let subject = session
85        .logout_subject()
86        .ok_or("session has no logout subject")?;
87    let logout = sp.start_slo(&idp_descriptor, subject, StartSlo::post())?;
88    println!("SP  -> LogoutRequest id = {}", logout.pending.id().as_str());
89
90    let logout_request = idp.receive_slo(
91        &sp_descriptor,
92        BrowserInput::<LogoutRequest>::post(logout.outbound.post_form()?.fields().to_vec()),
93        validation(),
94    )?;
95    let logout_response = idp.respond_slo(
96        &sp_descriptor,
97        &logout_request,
98        RespondSlo::post().relay_state(logout.pending.relay_state().clone()),
99    )?;
100    let completed = sp.finish_slo(
101        &idp_descriptor,
102        &logout.pending,
103        BrowserInput::<LogoutResponse>::post(logout_response.post_form()?.fields().to_vec()),
104        validation(),
105    )?;
106    println!(
107        "SP  <- LogoutResponse status = {}",
108        completed.status().unwrap_or("missing")
109    );
110    Ok(())
111}
Source

pub fn raw_service_provider(&self) -> &ServiceProvider

Raw compatibility Service Provider.

Source

pub fn start_sso( &self, idp: &IdpDescriptor, options: StartSso, ) -> Result<Started<AuthnRequest>, SamlError>

Start SP-initiated Web SSO.

§Errors

Returns SamlError when relay state is invalid, the IdP metadata cannot be parsed or trusted, the requested ACS is missing or conflicts with the selected binding, producer rules are combined with a custom AuthnRequest template, or request creation fails because required metadata, signing keys, or supported bindings are unavailable.

§Examples
use saml_rs::{
    AcsEndpoint, EntityId, IdpConfig, IdpDescriptor, IdpValidationPolicy,
    MetadataTrustPolicy, RelayStateParam, Saml, SpConfig, SpValidationPolicy,
    SsoEndpoint, StartSso,
};

let sp_config = SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
    .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
    .validation(SpValidationPolicy::compatibility())
    .build()?;
let idp_config = IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
    .sso_endpoint(SsoEndpoint::redirect("https://idp.example.com/sso")?)
    .validation(IdpValidationPolicy::compatibility())
    .build()?;

let sp = Saml::sp(sp_config)?;
let idp = Saml::idp(idp_config)?;
let idp = IdpDescriptor::from_metadata_xml(
    idp.metadata_xml(),
    MetadataTrustPolicy::UnsignedForCompatibility,
)?;
let relay_state = RelayStateParam::try_from_option(Some("state".to_string()))?;
let started = sp.start_sso(&idp, StartSso::redirect().relay_state(relay_state))?;

let redirect_url = started.outbound.redirect_url()?;
Examples found in repository?
examples/sso.rs (line 65)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    use saml_rs::{
18        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
19        IdpDescriptor, IdpValidationPolicy, MetadataTrustPolicy, NameId, PrivateKeyPem,
20        RelayStateParam, ReplayPolicy, RespondSso, Saml, SamlValidationContext, SpConfig,
21        SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .credentials(credentials())
40            .validation(SpValidationPolicy::strict())
41            .build()?,
42    )?;
43    let idp = Saml::idp(
44        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
45            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
46            .credentials(credentials())
47            .validation(IdpValidationPolicy::strict())
48            .build()?,
49    )?;
50
51    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
52        EntityId::try_new("https://sp.example.com/metadata")?,
53        sp.metadata_xml(),
54        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
55        MetadataTrustPolicy::UnsignedForCompatibility,
56    )?;
57    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
58        EntityId::try_new("https://idp.example.com/metadata")?,
59        idp.metadata_xml(),
60        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
61        MetadataTrustPolicy::UnsignedForCompatibility,
62    )?;
63
64    let relay_state = RelayStateParam::try_from_option(Some("demo-state".to_string()))?;
65    let started = sp.start_sso(&idp_descriptor, StartSso::post().relay_state(relay_state))?;
66    println!(
67        "SP  -> AuthnRequest id = {}",
68        started.pending.request_id().as_str()
69    );
70
71    let request = idp.receive_sso(
72        &sp_descriptor,
73        BrowserInput::<AuthnRequest>::post(started.outbound.post_form()?.fields().to_vec()),
74        validation(),
75    )?;
76    println!(
77        "IdP <- request issuer  = {}",
78        request.message().issuer().as_str()
79    );
80
81    let response = idp.respond_sso(
82        &sp_descriptor,
83        &request,
84        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
85        RespondSso::post(),
86    )?;
87
88    let session = sp.finish_sso(
89        &idp_descriptor,
90        &started.pending,
91        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
92        validation(),
93    );
94    let session = session?;
95    println!("SP  <- authenticated   = {}", session.name_id().value());
96    Ok(())
97}
More examples
Hide additional examples
examples/slo.rs (line 65)
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16    use saml_rs::{
17        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
18        IdpDescriptor, IdpValidationPolicy, LogoutRequest, LogoutResponse, MetadataTrustPolicy,
19        NameId, PrivateKeyPem, ReplayPolicy, RespondSlo, RespondSso, Saml, SamlValidationContext,
20        SloEndpoint, SpConfig, SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse,
21        StartSlo, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .slo_endpoint(SloEndpoint::post("https://sp.example.com/slo")?)
40            .credentials(credentials())
41            .validation(SpValidationPolicy::strict())
42            .build()?,
43    )?;
44    let idp = Saml::idp(
45        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
46            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
47            .slo_endpoint(SloEndpoint::post("https://idp.example.com/slo")?)
48            .credentials(credentials())
49            .validation(IdpValidationPolicy::strict())
50            .build()?,
51    )?;
52    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
53        EntityId::try_new("https://sp.example.com/metadata")?,
54        sp.metadata_xml(),
55        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
56        MetadataTrustPolicy::UnsignedForCompatibility,
57    )?;
58    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
59        EntityId::try_new("https://idp.example.com/metadata")?,
60        idp.metadata_xml(),
61        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
62        MetadataTrustPolicy::UnsignedForCompatibility,
63    )?;
64
65    let sso = sp.start_sso(&idp_descriptor, StartSso::post())?;
66    let request = idp.receive_sso(
67        &sp_descriptor,
68        BrowserInput::<AuthnRequest>::post(sso.outbound.post_form()?.fields().to_vec()),
69        validation(),
70    )?;
71    let response = idp.respond_sso(
72        &sp_descriptor,
73        &request,
74        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
75        RespondSso::post(),
76    )?;
77    let session = sp.finish_sso(
78        &idp_descriptor,
79        &sso.pending,
80        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
81        validation(),
82    )?;
83
84    let subject = session
85        .logout_subject()
86        .ok_or("session has no logout subject")?;
87    let logout = sp.start_slo(&idp_descriptor, subject, StartSlo::post())?;
88    println!("SP  -> LogoutRequest id = {}", logout.pending.id().as_str());
89
90    let logout_request = idp.receive_slo(
91        &sp_descriptor,
92        BrowserInput::<LogoutRequest>::post(logout.outbound.post_form()?.fields().to_vec()),
93        validation(),
94    )?;
95    let logout_response = idp.respond_slo(
96        &sp_descriptor,
97        &logout_request,
98        RespondSlo::post().relay_state(logout.pending.relay_state().clone()),
99    )?;
100    let completed = sp.finish_slo(
101        &idp_descriptor,
102        &logout.pending,
103        BrowserInput::<LogoutResponse>::post(logout_response.post_form()?.fields().to_vec()),
104        validation(),
105    )?;
106    println!(
107        "SP  <- LogoutResponse status = {}",
108        completed.status().unwrap_or("missing")
109    );
110    Ok(())
111}
Source

pub fn finish_sso( &self, idp: &IdpDescriptor, pending: &PendingAuthnRequest, input: BrowserInput<SsoResponse>, validation: SamlValidationContext<'_>, ) -> Result<SsoSession, SamlError>

Finish SP-initiated SSO using stored pending AuthnRequest state.

This accepts the response without applying an outstanding logout. Use Self::finish_sso_with_outstanding_logout to reject a later assertion that matches one.

§Errors

Returns SamlError when the response does not match the pending request, including issuer, binding, relay state, destination, recipient, or InResponseTo mismatches; when XML, signature, certificate trust, audience, condition, or time validation fails; when the assertions do not share one issuer and one principal; or when replay validation returns ReplayDetected or TimeWindowInvalid.

§Examples
use saml_rs::{
    BrowserInput, FormField, IdpDescriptor, PendingAuthnRequest, ReplayPolicy, Saml,
    SamlValidationContext, SsoResponse,
};
use std::time::SystemTime;

let validation = SamlValidationContext::new(
    SystemTime::now(),
    ReplayPolicy::DisabledForCompatibility,
);
let input = BrowserInput::<SsoResponse>::post(fields);
let session = sp.finish_sso(idp, pending, input, validation)?;

let name_id = session.name_id().value();
Examples found in repository?
examples/sso.rs (lines 88-93)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    use saml_rs::{
18        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
19        IdpDescriptor, IdpValidationPolicy, MetadataTrustPolicy, NameId, PrivateKeyPem,
20        RelayStateParam, ReplayPolicy, RespondSso, Saml, SamlValidationContext, SpConfig,
21        SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .credentials(credentials())
40            .validation(SpValidationPolicy::strict())
41            .build()?,
42    )?;
43    let idp = Saml::idp(
44        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
45            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
46            .credentials(credentials())
47            .validation(IdpValidationPolicy::strict())
48            .build()?,
49    )?;
50
51    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
52        EntityId::try_new("https://sp.example.com/metadata")?,
53        sp.metadata_xml(),
54        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
55        MetadataTrustPolicy::UnsignedForCompatibility,
56    )?;
57    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
58        EntityId::try_new("https://idp.example.com/metadata")?,
59        idp.metadata_xml(),
60        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
61        MetadataTrustPolicy::UnsignedForCompatibility,
62    )?;
63
64    let relay_state = RelayStateParam::try_from_option(Some("demo-state".to_string()))?;
65    let started = sp.start_sso(&idp_descriptor, StartSso::post().relay_state(relay_state))?;
66    println!(
67        "SP  -> AuthnRequest id = {}",
68        started.pending.request_id().as_str()
69    );
70
71    let request = idp.receive_sso(
72        &sp_descriptor,
73        BrowserInput::<AuthnRequest>::post(started.outbound.post_form()?.fields().to_vec()),
74        validation(),
75    )?;
76    println!(
77        "IdP <- request issuer  = {}",
78        request.message().issuer().as_str()
79    );
80
81    let response = idp.respond_sso(
82        &sp_descriptor,
83        &request,
84        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
85        RespondSso::post(),
86    )?;
87
88    let session = sp.finish_sso(
89        &idp_descriptor,
90        &started.pending,
91        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
92        validation(),
93    );
94    let session = session?;
95    println!("SP  <- authenticated   = {}", session.name_id().value());
96    Ok(())
97}
More examples
Hide additional examples
examples/slo.rs (lines 77-82)
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16    use saml_rs::{
17        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
18        IdpDescriptor, IdpValidationPolicy, LogoutRequest, LogoutResponse, MetadataTrustPolicy,
19        NameId, PrivateKeyPem, ReplayPolicy, RespondSlo, RespondSso, Saml, SamlValidationContext,
20        SloEndpoint, SpConfig, SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse,
21        StartSlo, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .slo_endpoint(SloEndpoint::post("https://sp.example.com/slo")?)
40            .credentials(credentials())
41            .validation(SpValidationPolicy::strict())
42            .build()?,
43    )?;
44    let idp = Saml::idp(
45        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
46            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
47            .slo_endpoint(SloEndpoint::post("https://idp.example.com/slo")?)
48            .credentials(credentials())
49            .validation(IdpValidationPolicy::strict())
50            .build()?,
51    )?;
52    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
53        EntityId::try_new("https://sp.example.com/metadata")?,
54        sp.metadata_xml(),
55        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
56        MetadataTrustPolicy::UnsignedForCompatibility,
57    )?;
58    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
59        EntityId::try_new("https://idp.example.com/metadata")?,
60        idp.metadata_xml(),
61        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
62        MetadataTrustPolicy::UnsignedForCompatibility,
63    )?;
64
65    let sso = sp.start_sso(&idp_descriptor, StartSso::post())?;
66    let request = idp.receive_sso(
67        &sp_descriptor,
68        BrowserInput::<AuthnRequest>::post(sso.outbound.post_form()?.fields().to_vec()),
69        validation(),
70    )?;
71    let response = idp.respond_sso(
72        &sp_descriptor,
73        &request,
74        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
75        RespondSso::post(),
76    )?;
77    let session = sp.finish_sso(
78        &idp_descriptor,
79        &sso.pending,
80        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
81        validation(),
82    )?;
83
84    let subject = session
85        .logout_subject()
86        .ok_or("session has no logout subject")?;
87    let logout = sp.start_slo(&idp_descriptor, subject, StartSlo::post())?;
88    println!("SP  -> LogoutRequest id = {}", logout.pending.id().as_str());
89
90    let logout_request = idp.receive_slo(
91        &sp_descriptor,
92        BrowserInput::<LogoutRequest>::post(logout.outbound.post_form()?.fields().to_vec()),
93        validation(),
94    )?;
95    let logout_response = idp.respond_slo(
96        &sp_descriptor,
97        &logout_request,
98        RespondSlo::post().relay_state(logout.pending.relay_state().clone()),
99    )?;
100    let completed = sp.finish_slo(
101        &idp_descriptor,
102        &logout.pending,
103        BrowserInput::<LogoutResponse>::post(logout_response.post_form()?.fields().to_vec()),
104        validation(),
105    )?;
106    println!(
107        "SP  <- LogoutResponse status = {}",
108        completed.status().unwrap_or("missing")
109    );
110    Ok(())
111}
Source

pub fn finish_sso_with_outstanding_logout( &self, idp: &IdpDescriptor, pending: &PendingAuthnRequest, input: BrowserInput<SsoResponse>, validation: SamlValidationContext<'_>, outstanding_logout: &OutstandingLogout, ) -> Result<SsoSession, SamlError>

Finish SP-initiated SSO and apply an OutstandingLogout.

A match is rejected. The assertion identifier is still recorded for replay.

§Errors

Returns SamlError::AssertionMatchesOutstandingLogout when the logout matches. Also returns the errors documented on Self::finish_sso.

Source

pub fn accept_unsolicited_sso( &self, idp: &IdpDescriptor, input: BrowserInput<SsoResponse>, validation: SamlValidationContext<'_>, ) -> Result<SsoSession, SamlError>

Accept an IdP-initiated SSO response explicitly.

This accepts the response without applying an outstanding logout. Use Self::accept_unsolicited_sso_with_outstanding_logout to reject a later assertion that matches one.

§Errors

Returns SamlError when the browser binding is not valid for SSO responses, RelayState exceeds 80 bytes, the IdP metadata cannot be parsed or trusted, XML parsing or signature verification fails, destination, recipient, audience, condition, or time validation fails, the assertions do not share one issuer and one principal, or replay validation returns ReplayDetected or TimeWindowInvalid.

Source

pub fn accept_unsolicited_sso_with_outstanding_logout( &self, idp: &IdpDescriptor, input: BrowserInput<SsoResponse>, validation: SamlValidationContext<'_>, outstanding_logout: &OutstandingLogout, ) -> Result<SsoSession, SamlError>

Accept an IdP-initiated SSO response and apply an OutstandingLogout.

§Errors

Returns the errors documented on Self::finish_sso_with_outstanding_logout and Self::accept_unsolicited_sso.

Source§

impl Saml

Source

pub fn sp(config: SpConfig) -> Result<Saml<Sp>, SamlError>

Build a typed Service Provider facade.

§Errors

Returns SamlError when the SP config cannot be converted into raw settings or metadata, including missing metadata, missing keys, or unsupported crypto configuration.

Examples found in repository?
examples/sso.rs (lines 36-42)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    use saml_rs::{
18        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
19        IdpDescriptor, IdpValidationPolicy, MetadataTrustPolicy, NameId, PrivateKeyPem,
20        RelayStateParam, ReplayPolicy, RespondSso, Saml, SamlValidationContext, SpConfig,
21        SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .credentials(credentials())
40            .validation(SpValidationPolicy::strict())
41            .build()?,
42    )?;
43    let idp = Saml::idp(
44        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
45            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
46            .credentials(credentials())
47            .validation(IdpValidationPolicy::strict())
48            .build()?,
49    )?;
50
51    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
52        EntityId::try_new("https://sp.example.com/metadata")?,
53        sp.metadata_xml(),
54        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
55        MetadataTrustPolicy::UnsignedForCompatibility,
56    )?;
57    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
58        EntityId::try_new("https://idp.example.com/metadata")?,
59        idp.metadata_xml(),
60        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
61        MetadataTrustPolicy::UnsignedForCompatibility,
62    )?;
63
64    let relay_state = RelayStateParam::try_from_option(Some("demo-state".to_string()))?;
65    let started = sp.start_sso(&idp_descriptor, StartSso::post().relay_state(relay_state))?;
66    println!(
67        "SP  -> AuthnRequest id = {}",
68        started.pending.request_id().as_str()
69    );
70
71    let request = idp.receive_sso(
72        &sp_descriptor,
73        BrowserInput::<AuthnRequest>::post(started.outbound.post_form()?.fields().to_vec()),
74        validation(),
75    )?;
76    println!(
77        "IdP <- request issuer  = {}",
78        request.message().issuer().as_str()
79    );
80
81    let response = idp.respond_sso(
82        &sp_descriptor,
83        &request,
84        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
85        RespondSso::post(),
86    )?;
87
88    let session = sp.finish_sso(
89        &idp_descriptor,
90        &started.pending,
91        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
92        validation(),
93    );
94    let session = session?;
95    println!("SP  <- authenticated   = {}", session.name_id().value());
96    Ok(())
97}
More examples
Hide additional examples
examples/slo.rs (lines 36-43)
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16    use saml_rs::{
17        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
18        IdpDescriptor, IdpValidationPolicy, LogoutRequest, LogoutResponse, MetadataTrustPolicy,
19        NameId, PrivateKeyPem, ReplayPolicy, RespondSlo, RespondSso, Saml, SamlValidationContext,
20        SloEndpoint, SpConfig, SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse,
21        StartSlo, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .slo_endpoint(SloEndpoint::post("https://sp.example.com/slo")?)
40            .credentials(credentials())
41            .validation(SpValidationPolicy::strict())
42            .build()?,
43    )?;
44    let idp = Saml::idp(
45        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
46            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
47            .slo_endpoint(SloEndpoint::post("https://idp.example.com/slo")?)
48            .credentials(credentials())
49            .validation(IdpValidationPolicy::strict())
50            .build()?,
51    )?;
52    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
53        EntityId::try_new("https://sp.example.com/metadata")?,
54        sp.metadata_xml(),
55        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
56        MetadataTrustPolicy::UnsignedForCompatibility,
57    )?;
58    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
59        EntityId::try_new("https://idp.example.com/metadata")?,
60        idp.metadata_xml(),
61        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
62        MetadataTrustPolicy::UnsignedForCompatibility,
63    )?;
64
65    let sso = sp.start_sso(&idp_descriptor, StartSso::post())?;
66    let request = idp.receive_sso(
67        &sp_descriptor,
68        BrowserInput::<AuthnRequest>::post(sso.outbound.post_form()?.fields().to_vec()),
69        validation(),
70    )?;
71    let response = idp.respond_sso(
72        &sp_descriptor,
73        &request,
74        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
75        RespondSso::post(),
76    )?;
77    let session = sp.finish_sso(
78        &idp_descriptor,
79        &sso.pending,
80        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
81        validation(),
82    )?;
83
84    let subject = session
85        .logout_subject()
86        .ok_or("session has no logout subject")?;
87    let logout = sp.start_slo(&idp_descriptor, subject, StartSlo::post())?;
88    println!("SP  -> LogoutRequest id = {}", logout.pending.id().as_str());
89
90    let logout_request = idp.receive_slo(
91        &sp_descriptor,
92        BrowserInput::<LogoutRequest>::post(logout.outbound.post_form()?.fields().to_vec()),
93        validation(),
94    )?;
95    let logout_response = idp.respond_slo(
96        &sp_descriptor,
97        &logout_request,
98        RespondSlo::post().relay_state(logout.pending.relay_state().clone()),
99    )?;
100    let completed = sp.finish_slo(
101        &idp_descriptor,
102        &logout.pending,
103        BrowserInput::<LogoutResponse>::post(logout_response.post_form()?.fields().to_vec()),
104        validation(),
105    )?;
106    println!(
107        "SP  <- LogoutResponse status = {}",
108        completed.status().unwrap_or("missing")
109    );
110    Ok(())
111}
Source

pub fn idp(config: IdpConfig) -> Result<Saml<Idp>, SamlError>

Build a typed Identity Provider facade.

§Errors

Returns SamlError when the IdP config cannot be converted into raw settings or metadata, including an invalid issuance lifetime, missing metadata, missing keys, or unsupported crypto configuration.

Examples found in repository?
examples/sso.rs (lines 43-49)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    use saml_rs::{
18        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
19        IdpDescriptor, IdpValidationPolicy, MetadataTrustPolicy, NameId, PrivateKeyPem,
20        RelayStateParam, ReplayPolicy, RespondSso, Saml, SamlValidationContext, SpConfig,
21        SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .credentials(credentials())
40            .validation(SpValidationPolicy::strict())
41            .build()?,
42    )?;
43    let idp = Saml::idp(
44        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
45            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
46            .credentials(credentials())
47            .validation(IdpValidationPolicy::strict())
48            .build()?,
49    )?;
50
51    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
52        EntityId::try_new("https://sp.example.com/metadata")?,
53        sp.metadata_xml(),
54        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
55        MetadataTrustPolicy::UnsignedForCompatibility,
56    )?;
57    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
58        EntityId::try_new("https://idp.example.com/metadata")?,
59        idp.metadata_xml(),
60        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
61        MetadataTrustPolicy::UnsignedForCompatibility,
62    )?;
63
64    let relay_state = RelayStateParam::try_from_option(Some("demo-state".to_string()))?;
65    let started = sp.start_sso(&idp_descriptor, StartSso::post().relay_state(relay_state))?;
66    println!(
67        "SP  -> AuthnRequest id = {}",
68        started.pending.request_id().as_str()
69    );
70
71    let request = idp.receive_sso(
72        &sp_descriptor,
73        BrowserInput::<AuthnRequest>::post(started.outbound.post_form()?.fields().to_vec()),
74        validation(),
75    )?;
76    println!(
77        "IdP <- request issuer  = {}",
78        request.message().issuer().as_str()
79    );
80
81    let response = idp.respond_sso(
82        &sp_descriptor,
83        &request,
84        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
85        RespondSso::post(),
86    )?;
87
88    let session = sp.finish_sso(
89        &idp_descriptor,
90        &started.pending,
91        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
92        validation(),
93    );
94    let session = session?;
95    println!("SP  <- authenticated   = {}", session.name_id().value());
96    Ok(())
97}
More examples
Hide additional examples
examples/slo.rs (lines 44-51)
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16    use saml_rs::{
17        AcsEndpoint, AuthnRequest, BrowserInput, CertificatePem, Credentials, EntityId, IdpConfig,
18        IdpDescriptor, IdpValidationPolicy, LogoutRequest, LogoutResponse, MetadataTrustPolicy,
19        NameId, PrivateKeyPem, ReplayPolicy, RespondSlo, RespondSso, Saml, SamlValidationContext,
20        SloEndpoint, SpConfig, SpDescriptor, SpValidationPolicy, SsoEndpoint, SsoResponse,
21        StartSlo, StartSso, Subject,
22    };
23    use std::time::SystemTime;
24
25    let privkey = include_str!("../tests/fixtures/key/sp_privkey.pem");
26    let cert = include_str!("../tests/fixtures/key/sp_signing_cert.cer");
27    let credentials = || Credentials {
28        signing_key: Some(PrivateKeyPem::new(privkey)),
29        signing_certificate: Some(CertificatePem::new(cert)),
30        ..Credentials::default()
31    };
32    // DisabledForCompatibility preserves the raw API, which has no replay cache.
33    let validation =
34        || SamlValidationContext::new(SystemTime::now(), ReplayPolicy::DisabledForCompatibility);
35
36    let sp = Saml::sp(
37        SpConfig::builder(EntityId::try_new("https://sp.example.com/metadata")?)
38            .acs_endpoint(AcsEndpoint::post("https://sp.example.com/acs")?)
39            .slo_endpoint(SloEndpoint::post("https://sp.example.com/slo")?)
40            .credentials(credentials())
41            .validation(SpValidationPolicy::strict())
42            .build()?,
43    )?;
44    let idp = Saml::idp(
45        IdpConfig::builder(EntityId::try_new("https://idp.example.com/metadata")?)
46            .sso_endpoint(SsoEndpoint::post("https://idp.example.com/sso")?)
47            .slo_endpoint(SloEndpoint::post("https://idp.example.com/slo")?)
48            .credentials(credentials())
49            .validation(IdpValidationPolicy::strict())
50            .build()?,
51    )?;
52    let sp_descriptor = SpDescriptor::from_metadata_xml_for(
53        EntityId::try_new("https://sp.example.com/metadata")?,
54        sp.metadata_xml(),
55        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
56        MetadataTrustPolicy::UnsignedForCompatibility,
57    )?;
58    let idp_descriptor = IdpDescriptor::from_metadata_xml_for(
59        EntityId::try_new("https://idp.example.com/metadata")?,
60        idp.metadata_xml(),
61        // UnsignedForCompatibility preserves an unsigned samlify-port metadata import.
62        MetadataTrustPolicy::UnsignedForCompatibility,
63    )?;
64
65    let sso = sp.start_sso(&idp_descriptor, StartSso::post())?;
66    let request = idp.receive_sso(
67        &sp_descriptor,
68        BrowserInput::<AuthnRequest>::post(sso.outbound.post_form()?.fields().to_vec()),
69        validation(),
70    )?;
71    let response = idp.respond_sso(
72        &sp_descriptor,
73        &request,
74        Subject::new(NameId::new("alice@example.com", None), Vec::new()),
75        RespondSso::post(),
76    )?;
77    let session = sp.finish_sso(
78        &idp_descriptor,
79        &sso.pending,
80        BrowserInput::<SsoResponse>::post(response.post_form()?.fields().to_vec()),
81        validation(),
82    )?;
83
84    let subject = session
85        .logout_subject()
86        .ok_or("session has no logout subject")?;
87    let logout = sp.start_slo(&idp_descriptor, subject, StartSlo::post())?;
88    println!("SP  -> LogoutRequest id = {}", logout.pending.id().as_str());
89
90    let logout_request = idp.receive_slo(
91        &sp_descriptor,
92        BrowserInput::<LogoutRequest>::post(logout.outbound.post_form()?.fields().to_vec()),
93        validation(),
94    )?;
95    let logout_response = idp.respond_slo(
96        &sp_descriptor,
97        &logout_request,
98        RespondSlo::post().relay_state(logout.pending.relay_state().clone()),
99    )?;
100    let completed = sp.finish_slo(
101        &idp_descriptor,
102        &logout.pending,
103        BrowserInput::<LogoutResponse>::post(logout_response.post_form()?.fields().to_vec()),
104        validation(),
105    )?;
106    println!(
107        "SP  <- LogoutResponse status = {}",
108        completed.status().unwrap_or("missing")
109    );
110    Ok(())
111}

Auto Trait Implementations§

§

impl<Role> Freeze for Saml<Role>
where Role: Freeze,

§

impl<Role> RefUnwindSafe for Saml<Role>
where Role: RefUnwindSafe,

§

impl<Role> Send for Saml<Role>
where Role: Send,

§

impl<Role> Sync for Saml<Role>
where Role: Sync,

§

impl<Role> Unpin for Saml<Role>
where Role: Unpin,

§

impl<Role> UnsafeUnpin for Saml<Role>
where Role: UnsafeUnpin,

§

impl<Role> UnwindSafe for Saml<Role>
where Role: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V