From 4a8fe92b1f86e86e78b152c117bb8feb31d130fd Mon Sep 17 00:00:00 2001 From: Daniel Wiesenberg Date: Wed, 10 Apr 2024 12:22:42 +0200 Subject: [PATCH 1/4] Implement `Extensions` struct --- src/schema/extensions.rs | 56 ++++++++++++++++++++++++++++++++++++++++ src/schema/mod.rs | 2 ++ 2 files changed, 58 insertions(+) create mode 100644 src/schema/extensions.rs diff --git a/src/schema/extensions.rs b/src/schema/extensions.rs new file mode 100644 index 0000000..38fde96 --- /dev/null +++ b/src/schema/extensions.rs @@ -0,0 +1,56 @@ +use std::io::{Cursor, Write}; + +use quick_xml::{ + events::{BytesEnd, BytesStart, BytesText, Event}, + Writer, +}; +use serde::Deserialize; + +const NAME: &str = "saml2p:Extensions"; + +#[derive(Clone, Debug, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd)] +pub struct Extensions(pub Vec); + +impl TryFrom for Event<'_> { + type Error = Box; + + fn try_from(value: Extensions) -> Result { + (&value).try_into() + } +} + +impl TryFrom<&Extensions> for Event<'_> { + type Error = Box; + + fn try_from(value: &Extensions) -> Result { + let mut write_buf = Vec::new(); + let mut writer = Writer::new(Cursor::new(&mut write_buf)); + let root = BytesStart::from_content(NAME, NAME.len()); + writer.write_event(Event::Start(root))?; + + for extension in &value.0 { + writer.get_mut().write_all(extension.as_bytes())?; + } + + writer.write_event(Event::End(BytesEnd::new(NAME)))?; + Ok(Event::Text(BytesText::from_escaped(String::from_utf8( + write_buf, + )?))) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::traits::ToXml; + + #[test] + fn extensions_xml_serialization() { + assert_eq!( + r#""#, + Extensions(vec![r#""#.to_string()]) + .to_xml() + .unwrap(), + ) + } +} diff --git a/src/schema/mod.rs b/src/schema/mod.rs index 5a30181..5d18cc8 100644 --- a/src/schema/mod.rs +++ b/src/schema/mod.rs @@ -1,5 +1,6 @@ pub mod authn_request; mod conditions; +mod extensions; mod issuer; mod name_id_policy; mod response; @@ -7,6 +8,7 @@ mod subject; pub use authn_request::AuthnRequest; pub use conditions::*; +pub use extensions::Extensions; pub use issuer::Issuer; pub use name_id_policy::NameIdPolicy; pub use response::Response; From 88b723102f6480dde36b15938669dccf6085e4d9 Mon Sep 17 00:00:00 2001 From: Daniel Wiesenberg Date: Wed, 10 Apr 2024 13:49:08 +0200 Subject: [PATCH 2/4] Add `Extensions` to `AuthnRequest` --- src/schema/authn_request.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/schema/authn_request.rs b/src/schema/authn_request.rs index f7e670b..39a6798 100644 --- a/src/schema/authn_request.rs +++ b/src/schema/authn_request.rs @@ -1,4 +1,4 @@ -use crate::schema::{Conditions, Issuer, NameIdPolicy, Subject}; +use crate::schema::{Conditions, Extensions, Issuer, NameIdPolicy, Subject}; use crate::signature::Signature; use chrono::prelude::*; use quick_xml::events::{BytesDecl, BytesEnd, BytesStart, BytesText, Event}; @@ -30,6 +30,8 @@ pub struct AuthnRequest { pub issuer: Option, #[serde(rename = "Signature")] pub signature: Option, + #[serde(rename = "Extensions")] + pub extensions: Option, #[serde(rename = "Subject")] pub subject: Option, #[serde(rename = "NameIDPolicy")] @@ -62,6 +64,7 @@ impl Default for AuthnRequest { consent: None, issuer: None, signature: None, + extensions: None, subject: None, name_id_policy: None, conditions: None, @@ -207,6 +210,10 @@ impl TryFrom<&AuthnRequest> for Event<'_> { let event: Event<'_> = signature.try_into()?; writer.write_event(event)?; } + if let Some(extensions) = &value.extensions { + let event: Event<'_> = extensions.try_into()?; + writer.write_event(event)?; + } if let Some(subject) = &value.subject { let event: Event<'_> = subject.try_into()?; writer.write_event(event)?; From 87420634236ed222b8ce218858739746df0a95a3 Mon Sep 17 00:00:00 2001 From: Daniel Wiesenberg Date: Wed, 10 Apr 2024 17:03:25 +0200 Subject: [PATCH 3/4] Update CHANGELOG --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index a25edfb..f761bc1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ # Changelog +### Unreleased +- Add ability to serialize and deserialize `Extensions` in an `AuthnRequest` + ### 0.0.15 - Updates dependencies From 3d1f52b903559624ae601ff61cef32e3b810a8d6 Mon Sep 17 00:00:00 2001 From: Daniel Wiesenberg Date: Fri, 19 Apr 2024 12:31:18 +0200 Subject: [PATCH 4/4] Skip deserializing `Extensions` because it does not work for arbitrary elements with the current quick_xml version --- src/schema/authn_request.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/schema/authn_request.rs b/src/schema/authn_request.rs index 39a6798..1e2c459 100644 --- a/src/schema/authn_request.rs +++ b/src/schema/authn_request.rs @@ -31,6 +31,7 @@ pub struct AuthnRequest { #[serde(rename = "Signature")] pub signature: Option, #[serde(rename = "Extensions")] + #[serde(skip_deserializing)] pub extensions: Option, #[serde(rename = "Subject")] pub subject: Option,