1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum Binding {
11 Redirect,
13 Post,
15 SimpleSign,
17 Artifact,
19}
20
21impl Binding {
22 pub fn urn(self) -> &'static str {
24 match self {
25 Binding::Redirect => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
26 Binding::Post => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
27 Binding::SimpleSign => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign",
28 Binding::Artifact => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact",
29 }
30 }
31
32 pub fn short_name(self) -> &'static str {
34 match self {
35 Binding::Redirect => "redirect",
36 Binding::Post => "post",
37 Binding::SimpleSign => "simpleSign",
38 Binding::Artifact => "artifact",
39 }
40 }
41
42 pub fn from_short_name(name: &str) -> Option<Self> {
44 match name {
45 "redirect" => Some(Binding::Redirect),
46 "post" => Some(Binding::Post),
47 "simpleSign" => Some(Binding::SimpleSign),
48 "artifact" => Some(Binding::Artifact),
49 _ => None,
50 }
51 }
52
53 pub fn from_urn(urn: &str) -> Option<Self> {
55 [
56 Binding::Redirect,
57 Binding::Post,
58 Binding::SimpleSign,
59 Binding::Artifact,
60 ]
61 .into_iter()
62 .find(|b| b.urn() == urn)
63 }
64}
65
66pub mod namespace {
68 pub const PROTOCOL: &str = "urn:oasis:names:tc:SAML:2.0:protocol";
70 pub const ASSERTION: &str = "urn:oasis:names:tc:SAML:2.0:assertion";
72 pub const METADATA: &str = "urn:oasis:names:tc:SAML:2.0:metadata";
74 pub const DSIG: &str = "http://www.w3.org/2000/09/xmldsig#";
76 pub const USER_LOGOUT: &str = "urn:oasis:names:tc:SAML:2.0:logout:user";
78 pub const ADMIN_LOGOUT: &str = "urn:oasis:names:tc:SAML:2.0:logout:admin";
80}
81
82pub mod name_id_format {
84 pub const EMAIL_ADDRESS: &str = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress";
86 pub const PERSISTENT: &str = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent";
88 pub const TRANSIENT: &str = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient";
90 pub const ENTITY: &str = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity";
92 pub const UNSPECIFIED: &str = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified";
94 pub const KERBEROS: &str = "urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos";
96 pub const WINDOWS_DOMAIN_QUALIFIED_NAME: &str =
98 "urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName";
99 pub const X509_SUBJECT_NAME: &str = "urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName";
101}
102
103pub mod authn_context_class_ref {
105 pub const PASSWORD: &str = "urn:oasis:names:tc:SAML:2.0:ac:classes:Password";
107 pub const PASSWORD_PROTECTED_TRANSPORT: &str =
109 "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport";
110}
111
112pub mod status_code {
114 pub const SUCCESS: &str = "urn:oasis:names:tc:SAML:2.0:status:Success";
117 pub const REQUESTER: &str = "urn:oasis:names:tc:SAML:2.0:status:Requester";
119 pub const RESPONDER: &str = "urn:oasis:names:tc:SAML:2.0:status:Responder";
121 pub const VERSION_MISMATCH: &str = "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch";
123 pub const AUTH_FAILED: &str = "urn:oasis:names:tc:SAML:2.0:status:AuthnFailed";
126 pub const INVALID_ATTR_NAME_OR_VALUE: &str =
128 "urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue";
129 pub const INVALID_NAME_ID_POLICY: &str =
131 "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy";
132 pub const NO_AUTHN_CONTEXT: &str = "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext";
134 pub const NO_AVAILABLE_IDP: &str = "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP";
136 pub const NO_PASSIVE: &str = "urn:oasis:names:tc:SAML:2.0:status:NoPassive";
138 pub const NO_SUPPORTED_IDP: &str = "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP";
140 pub const PARTIAL_LOGOUT: &str = "urn:oasis:names:tc:SAML:2.0:status:PartialLogout";
142 pub const PROXY_COUNT_EXCEEDED: &str = "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded";
144 pub const REQUEST_DENIED: &str = "urn:oasis:names:tc:SAML:2.0:status:RequestDenied";
146 pub const REQUEST_UNSUPPORTED: &str = "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported";
148 pub const REQUEST_VERSION_DEPRECATED: &str =
150 "urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated";
151 pub const REQUEST_VERSION_TOO_HIGH: &str =
153 "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh";
154 pub const REQUEST_VERSION_TOO_LOW: &str =
156 "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow";
157 pub const RESOURCE_NOT_RECOGNIZED: &str =
159 "urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized";
160 pub const TOO_MANY_RESPONSES: &str = "urn:oasis:names:tc:SAML:2.0:status:TooManyResponses";
162 pub const UNKNOWN_ATTR_PROFILE: &str = "urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile";
164 pub const UNKNOWN_PRINCIPAL: &str = "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal";
166 pub const UNSUPPORTED_BINDING: &str = "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding";
168}
169
170pub mod signature_algorithm {
172 pub const RSA_SHA1: &str = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
174 pub const RSA_SHA256: &str = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
176 pub const RSA_SHA256_MGF1: &str = "http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1";
178 pub const RSA_SHA384: &str = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384";
180 pub const RSA_SHA512: &str = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512";
182}
183
184pub mod digest_algorithm {
186 pub const SHA1: &str = "http://www.w3.org/2000/09/xmldsig#sha1";
188 pub const SHA256: &str = "http://www.w3.org/2001/04/xmlenc#sha256";
190 pub const SHA384: &str = "http://www.w3.org/2001/04/xmldsig-more#sha384";
192 pub const SHA512: &str = "http://www.w3.org/2001/04/xmlenc#sha512";
194}
195
196pub fn digest_for_signature(sig_alg: &str) -> Option<&'static str> {
198 match sig_alg {
199 signature_algorithm::RSA_SHA1 => Some(digest_algorithm::SHA1),
200 signature_algorithm::RSA_SHA256 => Some(digest_algorithm::SHA256),
201 signature_algorithm::RSA_SHA256_MGF1 => Some(digest_algorithm::SHA256),
202 signature_algorithm::RSA_SHA384 => Some(digest_algorithm::SHA384),
203 signature_algorithm::RSA_SHA512 => Some(digest_algorithm::SHA512),
204 _ => None,
205 }
206}
207
208pub mod data_encryption_algorithm {
210 pub const AES_128: &str = "http://www.w3.org/2001/04/xmlenc#aes128-cbc";
212 pub const AES_256: &str = "http://www.w3.org/2001/04/xmlenc#aes256-cbc";
214 pub const TRIPLE_DES: &str = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc";
216 pub const AES_128_GCM: &str = "http://www.w3.org/2009/xmlenc11#aes128-gcm";
218}
219
220pub(crate) fn is_xml_encryption_cbc_algorithm(algorithm: &str) -> bool {
221 matches!(
222 algorithm,
223 data_encryption_algorithm::AES_128
224 | data_encryption_algorithm::AES_256
225 | data_encryption_algorithm::TRIPLE_DES
226 )
227}
228
229pub mod key_encryption_algorithm {
231 pub const RSA_OAEP_MGF1P: &str = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p";
233 pub const RSA_1_5: &str = "http://www.w3.org/2001/04/xmlenc#rsa-1_5";
235}
236
237pub mod transform_algorithm {
239 pub const ENVELOPED_SIGNATURE: &str = "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
241 pub const EXC_C14N: &str = "http://www.w3.org/2001/10/xml-exc-c14n#";
243}
244
245pub mod url_params {
247 pub const SAML_REQUEST: &str = "SAMLRequest";
249 pub const SAML_RESPONSE: &str = "SAMLResponse";
251 pub const SIG_ALG: &str = "SigAlg";
253 pub const SIGNATURE: &str = "Signature";
255 pub const RELAY_STATE: &str = "RelayState";
257}
258
259#[derive(Debug, Clone, Copy, PartialEq, Eq)]
261pub enum CertUse {
262 Signing,
264 Encryption,
266}
267
268impl CertUse {
269 pub fn as_str(self) -> &'static str {
271 match self {
272 CertUse::Signing => "signing",
273 CertUse::Encryption => "encryption",
274 }
275 }
276}
277
278#[derive(Debug, Clone, Copy, PartialEq, Eq)]
280pub enum MessageSignatureOrder {
281 SignThenEncrypt,
283 EncryptThenSign,
285}
286
287impl MessageSignatureOrder {
288 pub fn as_str(self) -> &'static str {
290 match self {
291 MessageSignatureOrder::SignThenEncrypt => "sign-then-encrypt",
292 MessageSignatureOrder::EncryptThenSign => "encrypt-then-sign",
293 }
294 }
295}
296
297#[derive(Debug, Clone, Copy, PartialEq, Eq)]
299pub enum ParserType {
300 SamlRequest,
302 SamlResponse,
304 LogoutRequest,
306 LogoutResponse,
308}
309
310impl ParserType {
311 pub fn as_str(self) -> &'static str {
313 match self {
314 ParserType::SamlRequest => "SAMLRequest",
315 ParserType::SamlResponse => "SAMLResponse",
316 ParserType::LogoutRequest => "LogoutRequest",
317 ParserType::LogoutResponse => "LogoutResponse",
318 }
319 }
320
321 pub fn query_param(self) -> &'static str {
324 match self {
325 ParserType::SamlRequest | ParserType::LogoutRequest => url_params::SAML_REQUEST,
326 ParserType::SamlResponse | ParserType::LogoutResponse => url_params::SAML_RESPONSE,
327 }
328 }
329}
330
331pub mod elements_order {
335 pub const DEFAULT: &[&str] = &[
337 "KeyDescriptor",
338 "NameIDFormat",
339 "SingleLogoutService",
340 "AssertionConsumerService",
341 ];
342 pub const ONELOGIN: &[&str] = DEFAULT;
344 pub const SHIBBOLETH: &[&str] = &[
346 "KeyDescriptor",
347 "SingleLogoutService",
348 "NameIDFormat",
349 "AssertionConsumerService",
350 "AttributeConsumingService",
351 ];
352
353 pub mod idp {
355 pub const DEFAULT: &[&str] = &[
357 "KeyDescriptor",
358 "NameIDFormat",
359 "SingleSignOnService",
360 "SingleLogoutService",
361 ];
362 pub const ONELOGIN: &[&str] = &[
364 "KeyDescriptor",
365 "NameIDFormat",
366 "SingleLogoutService",
367 "SingleSignOnService",
368 ];
369 pub const SHIBBOLETH: &[&str] = &[
371 "KeyDescriptor",
372 "SingleLogoutService",
373 "NameIDFormat",
374 "SingleSignOnService",
375 ];
376 }
377}
378
379#[cfg(test)]
380mod tests {
381 use super::*;
382
383 #[test]
384 fn binding_urns_match_saml_spec_values() {
385 assert_eq!(
386 Binding::Redirect.urn(),
387 "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
388 );
389 assert_eq!(
390 Binding::Post.urn(),
391 "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
392 );
393 assert_eq!(
394 Binding::SimpleSign.urn(),
395 "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
396 );
397 assert_eq!(
398 Binding::Artifact.urn(),
399 "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
400 );
401 }
402
403 #[test]
404 fn binding_short_name_round_trip() {
405 for b in [
406 Binding::Redirect,
407 Binding::Post,
408 Binding::SimpleSign,
409 Binding::Artifact,
410 ] {
411 assert_eq!(Binding::from_short_name(b.short_name()), Some(b));
412 assert_eq!(Binding::from_urn(b.urn()), Some(b));
413 }
414 assert_eq!(Binding::from_short_name("nope"), None);
415 assert_eq!(Binding::from_urn("nope"), None);
416 }
417
418 #[test]
419 fn parser_type_query_param() {
420 assert_eq!(ParserType::SamlRequest.query_param(), "SAMLRequest");
421 assert_eq!(ParserType::LogoutRequest.query_param(), "SAMLRequest");
422 assert_eq!(ParserType::SamlResponse.query_param(), "SAMLResponse");
423 assert_eq!(ParserType::LogoutResponse.query_param(), "SAMLResponse");
424 }
425
426 #[test]
427 fn digest_mapping_matches_xmlsig_values() {
428 assert_eq!(
429 digest_for_signature(signature_algorithm::RSA_SHA256),
430 Some(digest_algorithm::SHA256)
431 );
432 assert_eq!(
433 digest_for_signature(signature_algorithm::RSA_SHA256_MGF1),
434 Some(digest_algorithm::SHA256)
435 );
436 assert_eq!(
437 digest_for_signature(signature_algorithm::RSA_SHA1),
438 Some("http://www.w3.org/2000/09/xmldsig#sha1")
439 );
440 assert_eq!(digest_for_signature("unknown"), None);
441 }
442
443 #[test]
444 fn status_success_value() {
445 assert_eq!(
446 status_code::SUCCESS,
447 "urn:oasis:names:tc:SAML:2.0:status:Success"
448 );
449 }
450
451 #[test]
452 fn elements_order_profiles() {
453 assert_eq!(elements_order::DEFAULT.len(), 4);
454 assert_eq!(elements_order::ONELOGIN, elements_order::DEFAULT);
455 assert_eq!(elements_order::SHIBBOLETH[1], "SingleLogoutService");
456 }
457}