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 mod key_encryption_algorithm {
222 pub const RSA_OAEP_MGF1P: &str = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p";
224 pub const RSA_1_5: &str = "http://www.w3.org/2001/04/xmlenc#rsa-1_5";
226}
227
228pub mod transform_algorithm {
230 pub const ENVELOPED_SIGNATURE: &str = "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
232 pub const EXC_C14N: &str = "http://www.w3.org/2001/10/xml-exc-c14n#";
234}
235
236pub mod url_params {
238 pub const SAML_REQUEST: &str = "SAMLRequest";
240 pub const SAML_RESPONSE: &str = "SAMLResponse";
242 pub const SIG_ALG: &str = "SigAlg";
244 pub const SIGNATURE: &str = "Signature";
246 pub const RELAY_STATE: &str = "RelayState";
248}
249
250#[derive(Debug, Clone, Copy, PartialEq, Eq)]
252pub enum CertUse {
253 Signing,
255 Encryption,
257}
258
259impl CertUse {
260 pub fn as_str(self) -> &'static str {
262 match self {
263 CertUse::Signing => "signing",
264 CertUse::Encryption => "encryption",
265 }
266 }
267}
268
269#[derive(Debug, Clone, Copy, PartialEq, Eq)]
271pub enum MessageSignatureOrder {
272 SignThenEncrypt,
274 EncryptThenSign,
276}
277
278impl MessageSignatureOrder {
279 pub fn as_str(self) -> &'static str {
281 match self {
282 MessageSignatureOrder::SignThenEncrypt => "sign-then-encrypt",
283 MessageSignatureOrder::EncryptThenSign => "encrypt-then-sign",
284 }
285 }
286}
287
288#[derive(Debug, Clone, Copy, PartialEq, Eq)]
290pub enum ParserType {
291 SamlRequest,
293 SamlResponse,
295 LogoutRequest,
297 LogoutResponse,
299}
300
301impl ParserType {
302 pub fn as_str(self) -> &'static str {
304 match self {
305 ParserType::SamlRequest => "SAMLRequest",
306 ParserType::SamlResponse => "SAMLResponse",
307 ParserType::LogoutRequest => "LogoutRequest",
308 ParserType::LogoutResponse => "LogoutResponse",
309 }
310 }
311
312 pub fn query_param(self) -> &'static str {
315 match self {
316 ParserType::SamlRequest | ParserType::LogoutRequest => url_params::SAML_REQUEST,
317 ParserType::SamlResponse | ParserType::LogoutResponse => url_params::SAML_RESPONSE,
318 }
319 }
320}
321
322pub mod elements_order {
326 pub const DEFAULT: &[&str] = &[
328 "KeyDescriptor",
329 "NameIDFormat",
330 "SingleLogoutService",
331 "AssertionConsumerService",
332 ];
333 pub const ONELOGIN: &[&str] = DEFAULT;
335 pub const SHIBBOLETH: &[&str] = &[
337 "KeyDescriptor",
338 "SingleLogoutService",
339 "NameIDFormat",
340 "AssertionConsumerService",
341 "AttributeConsumingService",
342 ];
343
344 pub mod idp {
346 pub const DEFAULT: &[&str] = &[
348 "KeyDescriptor",
349 "NameIDFormat",
350 "SingleSignOnService",
351 "SingleLogoutService",
352 ];
353 pub const ONELOGIN: &[&str] = &[
355 "KeyDescriptor",
356 "NameIDFormat",
357 "SingleLogoutService",
358 "SingleSignOnService",
359 ];
360 pub const SHIBBOLETH: &[&str] = &[
362 "KeyDescriptor",
363 "SingleLogoutService",
364 "NameIDFormat",
365 "SingleSignOnService",
366 ];
367 }
368}
369
370#[cfg(test)]
371mod tests {
372 use super::*;
373
374 #[test]
375 fn binding_urns_match_saml_spec_values() {
376 assert_eq!(
377 Binding::Redirect.urn(),
378 "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
379 );
380 assert_eq!(
381 Binding::Post.urn(),
382 "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
383 );
384 assert_eq!(
385 Binding::SimpleSign.urn(),
386 "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
387 );
388 assert_eq!(
389 Binding::Artifact.urn(),
390 "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
391 );
392 }
393
394 #[test]
395 fn binding_short_name_round_trip() {
396 for b in [
397 Binding::Redirect,
398 Binding::Post,
399 Binding::SimpleSign,
400 Binding::Artifact,
401 ] {
402 assert_eq!(Binding::from_short_name(b.short_name()), Some(b));
403 assert_eq!(Binding::from_urn(b.urn()), Some(b));
404 }
405 assert_eq!(Binding::from_short_name("nope"), None);
406 assert_eq!(Binding::from_urn("nope"), None);
407 }
408
409 #[test]
410 fn parser_type_query_param() {
411 assert_eq!(ParserType::SamlRequest.query_param(), "SAMLRequest");
412 assert_eq!(ParserType::LogoutRequest.query_param(), "SAMLRequest");
413 assert_eq!(ParserType::SamlResponse.query_param(), "SAMLResponse");
414 assert_eq!(ParserType::LogoutResponse.query_param(), "SAMLResponse");
415 }
416
417 #[test]
418 fn digest_mapping_matches_xmlsig_values() {
419 assert_eq!(
420 digest_for_signature(signature_algorithm::RSA_SHA256),
421 Some(digest_algorithm::SHA256)
422 );
423 assert_eq!(
424 digest_for_signature(signature_algorithm::RSA_SHA256_MGF1),
425 Some(digest_algorithm::SHA256)
426 );
427 assert_eq!(
428 digest_for_signature(signature_algorithm::RSA_SHA1),
429 Some("http://www.w3.org/2000/09/xmldsig#sha1")
430 );
431 assert_eq!(digest_for_signature("unknown"), None);
432 }
433
434 #[test]
435 fn status_success_value() {
436 assert_eq!(
437 status_code::SUCCESS,
438 "urn:oasis:names:tc:SAML:2.0:status:Success"
439 );
440 }
441
442 #[test]
443 fn elements_order_profiles() {
444 assert_eq!(elements_order::DEFAULT.len(), 4);
445 assert_eq!(elements_order::ONELOGIN, elements_order::DEFAULT);
446 assert_eq!(elements_order::SHIBBOLETH[1], "SingleLogoutService");
447 }
448}