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 pub const EXC_C14N_WITH_COMMENTS: &str = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments";
245}
246
247pub mod url_params {
249 pub const SAML_REQUEST: &str = "SAMLRequest";
251 pub const SAML_RESPONSE: &str = "SAMLResponse";
253 pub const SIG_ALG: &str = "SigAlg";
255 pub const SIGNATURE: &str = "Signature";
257 pub const RELAY_STATE: &str = "RelayState";
259}
260
261#[derive(Debug, Clone, Copy, PartialEq, Eq)]
263pub enum CertUse {
264 Signing,
266 Encryption,
268}
269
270impl CertUse {
271 pub fn as_str(self) -> &'static str {
273 match self {
274 CertUse::Signing => "signing",
275 CertUse::Encryption => "encryption",
276 }
277 }
278}
279
280#[derive(Debug, Clone, Copy, PartialEq, Eq)]
282pub enum MessageSignatureOrder {
283 SignThenEncrypt,
285 EncryptThenSign,
287}
288
289impl MessageSignatureOrder {
290 pub fn as_str(self) -> &'static str {
292 match self {
293 MessageSignatureOrder::SignThenEncrypt => "sign-then-encrypt",
294 MessageSignatureOrder::EncryptThenSign => "encrypt-then-sign",
295 }
296 }
297}
298
299#[derive(Debug, Clone, Copy, PartialEq, Eq)]
301pub enum ParserType {
302 SamlRequest,
304 SamlResponse,
306 LogoutRequest,
308 LogoutResponse,
310}
311
312impl ParserType {
313 pub fn as_str(self) -> &'static str {
315 match self {
316 ParserType::SamlRequest => "SAMLRequest",
317 ParserType::SamlResponse => "SAMLResponse",
318 ParserType::LogoutRequest => "LogoutRequest",
319 ParserType::LogoutResponse => "LogoutResponse",
320 }
321 }
322
323 pub fn query_param(self) -> &'static str {
326 match self {
327 ParserType::SamlRequest | ParserType::LogoutRequest => url_params::SAML_REQUEST,
328 ParserType::SamlResponse | ParserType::LogoutResponse => url_params::SAML_RESPONSE,
329 }
330 }
331}
332
333pub mod elements_order {
337 pub const DEFAULT: &[&str] = &[
339 "KeyDescriptor",
340 "NameIDFormat",
341 "SingleLogoutService",
342 "AssertionConsumerService",
343 ];
344 pub const ONELOGIN: &[&str] = DEFAULT;
346 pub const SHIBBOLETH: &[&str] = &[
348 "KeyDescriptor",
349 "SingleLogoutService",
350 "NameIDFormat",
351 "AssertionConsumerService",
352 "AttributeConsumingService",
353 ];
354
355 pub mod idp {
357 pub const DEFAULT: &[&str] = &[
359 "KeyDescriptor",
360 "NameIDFormat",
361 "SingleSignOnService",
362 "SingleLogoutService",
363 ];
364 pub const ONELOGIN: &[&str] = &[
366 "KeyDescriptor",
367 "NameIDFormat",
368 "SingleLogoutService",
369 "SingleSignOnService",
370 ];
371 pub const SHIBBOLETH: &[&str] = &[
373 "KeyDescriptor",
374 "SingleLogoutService",
375 "NameIDFormat",
376 "SingleSignOnService",
377 ];
378 }
379}
380
381#[cfg(test)]
382mod tests {
383 use super::*;
384
385 #[test]
386 fn binding_urns_match_saml_spec_values() {
387 assert_eq!(
388 Binding::Redirect.urn(),
389 "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
390 );
391 assert_eq!(
392 Binding::Post.urn(),
393 "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
394 );
395 assert_eq!(
396 Binding::SimpleSign.urn(),
397 "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
398 );
399 assert_eq!(
400 Binding::Artifact.urn(),
401 "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
402 );
403 }
404
405 #[test]
406 fn binding_short_name_round_trip() {
407 for b in [
408 Binding::Redirect,
409 Binding::Post,
410 Binding::SimpleSign,
411 Binding::Artifact,
412 ] {
413 assert_eq!(Binding::from_short_name(b.short_name()), Some(b));
414 assert_eq!(Binding::from_urn(b.urn()), Some(b));
415 }
416 assert_eq!(Binding::from_short_name("nope"), None);
417 assert_eq!(Binding::from_urn("nope"), None);
418 }
419
420 #[test]
421 fn parser_type_query_param() {
422 assert_eq!(ParserType::SamlRequest.query_param(), "SAMLRequest");
423 assert_eq!(ParserType::LogoutRequest.query_param(), "SAMLRequest");
424 assert_eq!(ParserType::SamlResponse.query_param(), "SAMLResponse");
425 assert_eq!(ParserType::LogoutResponse.query_param(), "SAMLResponse");
426 }
427
428 #[test]
429 fn digest_mapping_matches_xmlsig_values() {
430 assert_eq!(
431 digest_for_signature(signature_algorithm::RSA_SHA256),
432 Some(digest_algorithm::SHA256)
433 );
434 assert_eq!(
435 digest_for_signature(signature_algorithm::RSA_SHA256_MGF1),
436 Some(digest_algorithm::SHA256)
437 );
438 assert_eq!(
439 digest_for_signature(signature_algorithm::RSA_SHA1),
440 Some("http://www.w3.org/2000/09/xmldsig#sha1")
441 );
442 assert_eq!(digest_for_signature("unknown"), None);
443 }
444
445 #[test]
446 fn status_success_value() {
447 assert_eq!(
448 status_code::SUCCESS,
449 "urn:oasis:names:tc:SAML:2.0:status:Success"
450 );
451 }
452
453 #[test]
454 fn elements_order_profiles() {
455 assert_eq!(elements_order::DEFAULT.len(), 4);
456 assert_eq!(elements_order::ONELOGIN, elements_order::DEFAULT);
457 assert_eq!(elements_order::SHIBBOLETH[1], "SingleLogoutService");
458 }
459}