pub struct SamlValidationContext<'a> { /* private fields */ }Expand description
Caller-owned validation context for typed inbound SAML messages.
Implementations§
Source§impl<'a> SamlValidationContext<'a>
impl<'a> SamlValidationContext<'a>
Sourcepub fn new(now: SystemTime, replay: ReplayPolicy<'a>) -> Self
pub fn new(now: SystemTime, replay: ReplayPolicy<'a>) -> Self
Build a validation context that allows five minutes of clock skew.
The same skew covers assertion conditions, bearer confirmation,
SessionNotOnOrAfter, and LogoutRequest@NotOnOrAfter.
Self::with_clock_skew replaces it.
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}More examples
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 with_clock_skew(self, clock_skew: ClockSkew) -> Self
pub fn with_clock_skew(self, clock_skew: ClockSkew) -> Self
Replace the context clock skew, including ClockSkew::strict.
Sourcepub fn with_authn_request_age(
self,
authn_request_age: AuthnRequestAgePolicy,
) -> Self
pub fn with_authn_request_age( self, authn_request_age: AuthnRequestAgePolicy, ) -> Self
Select the maximum age of an inbound AuthnRequest IssueInstant.
AuthnRequestAgePolicy::Disabled skips the comparison.
AuthnRequestAgePolicy::Bounded accepts an instant at or after
now - max_age - past_tolerance and at or before
now + future_tolerance. Both edges are inclusive. Past tolerance is
the positive NotOnOrAfter skew. Future tolerance is the magnitude of
a negative NotBefore skew. Zero skew and inverted skew do not shrink
max_age.
Sourcepub fn with_replay_retention(self, retention: Duration) -> Self
pub fn with_replay_retention(self, retention: Duration) -> Self
Set explicit replay retention for protocol messages that do not carry a
SAML NotOnOrAfter value suitable for cache expiry.
Sourcepub fn now(&self) -> SystemTime
pub fn now(&self) -> SystemTime
Validation instant supplied by the caller.
Sourcepub fn clock_skew(&self) -> ClockSkew
pub fn clock_skew(&self) -> ClockSkew
Clock skew applied to time-window checks.
Sourcepub fn authn_request_age(&self) -> AuthnRequestAgePolicy
pub fn authn_request_age(&self) -> AuthnRequestAgePolicy
Maximum age policy for an inbound AuthnRequest IssueInstant.
Sourcepub fn replay_retention(&self) -> Option<Duration>
pub fn replay_retention(&self) -> Option<Duration>
Replay retention for protocol message IDs without SAML expiry.