pub struct SsoSession { /* private fields */ }Expand description
Parsed SSO login session.
Implementations§
Source§impl SsoSession
impl SsoSession
Sourcepub fn response_id(&self) -> &MessageId
pub fn response_id(&self) -> &MessageId
Response ID.
Sourcepub fn response_issue_instant(&self) -> &SamlInstant
pub fn response_issue_instant(&self) -> &SamlInstant
Response IssueInstant, normalized according to XML Schema whitespace rules.
Sourcepub fn assertion_id(&self) -> &AssertionId
pub fn assertion_id(&self) -> &AssertionId
Assertion ID.
Sourcepub fn assertion_issue_instant(&self) -> &SamlInstant
pub fn assertion_issue_instant(&self) -> &SamlInstant
Selected assertion IssueInstant, normalized according to XML Schema whitespace rules.
Sourcepub fn in_response_to(&self) -> Option<&MessageId>
pub fn in_response_to(&self) -> Option<&MessageId>
InResponseTo, when present.
Sourcepub fn name_id(&self) -> &NameId
pub fn name_id(&self) -> &NameId
Subject NameID.
Examples found in repository?
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}Sourcepub fn attributes(&self) -> &Attributes
pub fn attributes(&self) -> &Attributes
Attributes.
Sourcepub fn authn_session(&self) -> &AuthnSession
pub fn authn_session(&self) -> &AuthnSession
Legacy singular view of AuthnStatement session data.
This compatibility accessor returns the first statement in document
order. For assertions containing multiple statements, use
Self::authn_sessions. When no statement is present, it returns an
immutable empty AuthnSession.
Sourcepub fn authn_sessions(&self) -> &[AuthnSession]
pub fn authn_sessions(&self) -> &[AuthnSession]
Every AuthnStatement session tuple in XML document order.
Sourcepub fn not_before(&self) -> Option<&SamlInstant>
pub fn not_before(&self) -> Option<&SamlInstant>
Conditions NotBefore.
Sourcepub fn not_on_or_after(&self) -> Option<&SamlInstant>
pub fn not_on_or_after(&self) -> Option<&SamlInstant>
Conditions NotOnOrAfter.
Sourcepub fn sig_alg(&self) -> Option<&str>
pub fn sig_alg(&self) -> Option<&str>
Verified detached Redirect or HTTP-POST-SimpleSign algorithm, when applicable.
Embedded XML signatures are exposed separately through
Self::verified_xml_signatures because a message can contain multiple
verified signatures with different algorithms and coverage.
Sourcepub fn verified_xml_signatures(&self) -> &[VerifiedXmlSignature]
pub fn verified_xml_signatures(&self) -> &[VerifiedXmlSignature]
Successfully verified embedded XML signatures that authenticate this session’s Response root or consumed Assertion.
Each item is bound to one exact verifier-approved signature node and its verified references. Invalid, untrusted, malformed, or unrelated signatures are not included. The view preserves distinct signatures; it does not select a signature by XML order. Applications may inspect the reported algorithm URIs to enforce their own allowlist.
Sourcepub fn logout_subject(&self) -> Option<LogoutSubject>
pub fn logout_subject(&self) -> Option<LogoutSubject>
Subject data suitable for issuing Single Logout.
Every present SessionIndex is included in AuthnStatement document
order.
§Examples
use saml_rs::{IdpDescriptor, Saml, SamlError, SsoSession, StartSlo};
let subject = session
.logout_subject()
.ok_or_else(|| SamlError::Invalid("missing logout subject".into()))?;
let started = sp.start_slo(idp, subject, StartSlo::redirect())?;
let redirect_url = started.outbound.redirect_url()?;Examples found in repository?
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}Sourcepub fn replay_keys(&self) -> Vec<ReplayKey>
pub fn replay_keys(&self) -> Vec<ReplayKey>
Replay keys available from this validated SSO session.
Sourcepub fn check_and_store_replay(
&self,
validation: &mut SamlValidationContext<'_>,
) -> Result<(), SamlError>
pub fn check_and_store_replay( &self, validation: &mut SamlValidationContext<'_>, ) -> Result<(), SamlError>
Check and store this session’s replay keys using the caller cache.
This method is intended for typed inbound SSO facades. It should be
called only after signature, issuer, audience, destination, recipient,
InResponseTo, and time validation have already passed.
The bearer assertion identifier is kept until
SubjectConfirmationData@NotOnOrAfter plus skew. An earlier
Conditions or AuthnStatement instant does not shorten it. The
Response identifier still expires at the earliest bound. Every direct
assertion identifier is stored. Another assertion uses its own bearer
NotOnOrAfter when that attribute is present.
§Errors
Returns SamlError::TimeWindowInvalid when no valid replay
expiration can be derived or a stored deadline has already passed.
Nothing is stored in that case. Returns SamlError::ReplayDetected
when any session replay key has already been seen. Cache
implementations may also return storage-specific failures mapped to
SamlError.
Sourcepub fn raw_flow(&self) -> &FlowResult
pub fn raw_flow(&self) -> &FlowResult
Raw validated flow result.