wae_authentication/saml/
request.rs1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use super::config::{NameIdFormat, SamlBinding};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct SamlAuthnRequest {
11 #[serde(rename = "@ID")]
13 pub id: String,
14
15 #[serde(rename = "@Version")]
17 pub version: String,
18
19 #[serde(rename = "@IssueInstant")]
21 pub issue_instant: DateTime<Utc>,
22
23 #[serde(rename = "@Destination")]
25 pub destination: Option<String>,
26
27 #[serde(rename = "@ProtocolBinding")]
29 pub protocol_binding: Option<String>,
30
31 #[serde(rename = "@AssertionConsumerServiceURL")]
33 pub assertion_consumer_service_url: Option<String>,
34
35 #[serde(rename = "saml:Issuer")]
37 pub issuer: String,
38
39 #[serde(rename = "samlp:NameIDPolicy")]
41 pub name_id_policy: Option<SamlNameIdPolicy>,
42
43 #[serde(rename = "samlp:RequestedAuthnContext")]
45 pub requested_authn_context: Option<SamlRequestedAuthnContext>,
46
47 #[serde(rename = "ds:Signature")]
49 pub signature: Option<String>,
50}
51
52impl SamlAuthnRequest {
53 pub fn new(id: impl Into<String>, issuer: impl Into<String>) -> Self {
55 Self {
56 id: id.into(),
57 version: "2.0".to_string(),
58 issue_instant: Utc::now(),
59 destination: None,
60 protocol_binding: None,
61 assertion_consumer_service_url: None,
62 issuer: issuer.into(),
63 name_id_policy: None,
64 requested_authn_context: None,
65 signature: None,
66 }
67 }
68
69 pub fn with_destination(mut self, destination: impl Into<String>) -> Self {
71 self.destination = Some(destination.into());
72 self
73 }
74
75 pub fn with_protocol_binding(mut self, binding: SamlBinding) -> Self {
77 self.protocol_binding = Some(binding.uri().to_string());
78 self
79 }
80
81 pub fn with_acs_url(mut self, url: impl Into<String>) -> Self {
83 self.assertion_consumer_service_url = Some(url.into());
84 self
85 }
86
87 pub fn with_name_id_policy(mut self, policy: SamlNameIdPolicy) -> Self {
89 self.name_id_policy = Some(policy);
90 self
91 }
92
93 pub fn with_authn_context(mut self, context: SamlRequestedAuthnContext) -> Self {
95 self.requested_authn_context = Some(context);
96 self
97 }
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct SamlNameIdPolicy {
103 #[serde(rename = "@Format")]
105 pub format: Option<String>,
106
107 #[serde(rename = "@AllowCreate")]
109 pub allow_create: Option<bool>,
110
111 #[serde(rename = "@SPNameQualifier")]
113 pub sp_name_qualifier: Option<String>,
114}
115
116impl SamlNameIdPolicy {
117 pub fn new() -> Self {
119 Self { format: None, allow_create: None, sp_name_qualifier: None }
120 }
121
122 pub fn with_format(mut self, format: NameIdFormat) -> Self {
124 self.format = Some(format.uri().to_string());
125 self
126 }
127
128 pub fn with_allow_create(mut self, allow: bool) -> Self {
130 self.allow_create = Some(allow);
131 self
132 }
133}
134
135impl Default for SamlNameIdPolicy {
136 fn default() -> Self {
137 Self::new()
138 }
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct SamlRequestedAuthnContext {
144 #[serde(rename = "@Comparison")]
146 pub comparison: Option<String>,
147
148 #[serde(rename = "saml:AuthnContextClassRef")]
150 pub class_ref: Vec<String>,
151}
152
153impl SamlRequestedAuthnContext {
154 pub fn new(class_refs: Vec<String>) -> Self {
156 Self { comparison: None, class_ref: class_refs }
157 }
158
159 pub fn with_comparison(mut self, comparison: AuthnContextComparison) -> Self {
161 self.comparison = Some(comparison.as_str().to_string());
162 self
163 }
164}
165
166#[derive(Debug, Clone, Copy, PartialEq, Eq)]
168pub enum AuthnContextComparison {
169 Exact,
171 Better,
173 Maximum,
175 Minimum,
177}
178
179impl AuthnContextComparison {
180 pub fn as_str(&self) -> &'static str {
182 match self {
183 AuthnContextComparison::Exact => "exact",
184 AuthnContextComparison::Better => "better",
185 AuthnContextComparison::Maximum => "maximum",
186 AuthnContextComparison::Minimum => "minimum",
187 }
188 }
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
193pub struct SamlLogoutRequest {
194 #[serde(rename = "@ID")]
196 pub id: String,
197
198 #[serde(rename = "@Version")]
200 pub version: String,
201
202 #[serde(rename = "@IssueInstant")]
204 pub issue_instant: DateTime<Utc>,
205
206 #[serde(rename = "@Destination")]
208 pub destination: Option<String>,
209
210 #[serde(rename = "saml:Issuer")]
212 pub issuer: String,
213
214 #[serde(rename = "saml:NameID")]
216 pub name_id: Option<super::assertion::SamlNameId>,
217
218 #[serde(rename = "samlp:SessionIndex")]
220 pub session_index: Option<String>,
221
222 #[serde(rename = "ds:Signature")]
224 pub signature: Option<String>,
225}
226
227impl SamlLogoutRequest {
228 pub fn new(id: impl Into<String>, issuer: impl Into<String>) -> Self {
230 Self {
231 id: id.into(),
232 version: "2.0".to_string(),
233 issue_instant: Utc::now(),
234 destination: None,
235 issuer: issuer.into(),
236 name_id: None,
237 session_index: None,
238 signature: None,
239 }
240 }
241
242 pub fn with_destination(mut self, destination: impl Into<String>) -> Self {
244 self.destination = Some(destination.into());
245 self
246 }
247
248 pub fn with_name_id(mut self, name_id: super::assertion::SamlNameId) -> Self {
250 self.name_id = Some(name_id);
251 self
252 }
253
254 pub fn with_session_index(mut self, index: impl Into<String>) -> Self {
256 self.session_index = Some(index.into());
257 self
258 }
259}