#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Binding {
Redirect,
Post,
SimpleSign,
Artifact,
}
impl Binding {
pub fn urn(self) -> &'static str {
match self {
Binding::Redirect => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
Binding::Post => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
Binding::SimpleSign => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign",
Binding::Artifact => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact",
}
}
pub fn short_name(self) -> &'static str {
match self {
Binding::Redirect => "redirect",
Binding::Post => "post",
Binding::SimpleSign => "simpleSign",
Binding::Artifact => "artifact",
}
}
pub fn from_short_name(name: &str) -> Option<Self> {
match name {
"redirect" => Some(Binding::Redirect),
"post" => Some(Binding::Post),
"simpleSign" => Some(Binding::SimpleSign),
"artifact" => Some(Binding::Artifact),
_ => None,
}
}
pub fn from_urn(urn: &str) -> Option<Self> {
[
Binding::Redirect,
Binding::Post,
Binding::SimpleSign,
Binding::Artifact,
]
.into_iter()
.find(|b| b.urn() == urn)
}
}
pub mod namespace {
pub const PROTOCOL: &str = "urn:oasis:names:tc:SAML:2.0:protocol";
pub const ASSERTION: &str = "urn:oasis:names:tc:SAML:2.0:assertion";
pub const METADATA: &str = "urn:oasis:names:tc:SAML:2.0:metadata";
pub const DSIG: &str = "http://www.w3.org/2000/09/xmldsig#";
pub const USER_LOGOUT: &str = "urn:oasis:names:tc:SAML:2.0:logout:user";
pub const ADMIN_LOGOUT: &str = "urn:oasis:names:tc:SAML:2.0:logout:admin";
}
pub mod name_id_format {
pub const EMAIL_ADDRESS: &str = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress";
pub const PERSISTENT: &str = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent";
pub const TRANSIENT: &str = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient";
pub const ENTITY: &str = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity";
pub const UNSPECIFIED: &str = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified";
pub const KERBEROS: &str = "urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos";
pub const WINDOWS_DOMAIN_QUALIFIED_NAME: &str =
"urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName";
pub const X509_SUBJECT_NAME: &str = "urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName";
}
pub mod authn_context_class_ref {
pub const PASSWORD: &str = "urn:oasis:names:tc:SAML:2.0:ac:classes:Password";
pub const PASSWORD_PROTECTED_TRANSPORT: &str =
"urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport";
}
pub mod status_code {
pub const SUCCESS: &str = "urn:oasis:names:tc:SAML:2.0:status:Success";
pub const REQUESTER: &str = "urn:oasis:names:tc:SAML:2.0:status:Requester";
pub const RESPONDER: &str = "urn:oasis:names:tc:SAML:2.0:status:Responder";
pub const VERSION_MISMATCH: &str = "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch";
pub const AUTH_FAILED: &str = "urn:oasis:names:tc:SAML:2.0:status:AuthnFailed";
pub const INVALID_ATTR_NAME_OR_VALUE: &str =
"urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue";
pub const INVALID_NAME_ID_POLICY: &str =
"urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy";
pub const NO_AUTHN_CONTEXT: &str = "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext";
pub const NO_AVAILABLE_IDP: &str = "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP";
pub const NO_PASSIVE: &str = "urn:oasis:names:tc:SAML:2.0:status:NoPassive";
pub const NO_SUPPORTED_IDP: &str = "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP";
pub const PARTIAL_LOGOUT: &str = "urn:oasis:names:tc:SAML:2.0:status:PartialLogout";
pub const PROXY_COUNT_EXCEEDED: &str = "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded";
pub const REQUEST_DENIED: &str = "urn:oasis:names:tc:SAML:2.0:status:RequestDenied";
pub const REQUEST_UNSUPPORTED: &str = "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported";
pub const REQUEST_VERSION_DEPRECATED: &str =
"urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated";
pub const REQUEST_VERSION_TOO_HIGH: &str =
"urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh";
pub const REQUEST_VERSION_TOO_LOW: &str =
"urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow";
pub const RESOURCE_NOT_RECOGNIZED: &str =
"urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized";
pub const TOO_MANY_RESPONSES: &str = "urn:oasis:names:tc:SAML:2.0:status:TooManyResponses";
pub const UNKNOWN_ATTR_PROFILE: &str = "urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile";
pub const UNKNOWN_PRINCIPAL: &str = "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal";
pub const UNSUPPORTED_BINDING: &str = "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding";
}
pub mod signature_algorithm {
pub const RSA_SHA1: &str = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
pub const RSA_SHA256: &str = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
pub const RSA_SHA256_MGF1: &str = "http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1";
pub const RSA_SHA384: &str = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384";
pub const RSA_SHA512: &str = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512";
}
pub mod digest_algorithm {
pub const SHA1: &str = "http://www.w3.org/2000/09/xmldsig#sha1";
pub const SHA256: &str = "http://www.w3.org/2001/04/xmlenc#sha256";
pub const SHA384: &str = "http://www.w3.org/2001/04/xmldsig-more#sha384";
pub const SHA512: &str = "http://www.w3.org/2001/04/xmlenc#sha512";
}
pub fn digest_for_signature(sig_alg: &str) -> Option<&'static str> {
match sig_alg {
signature_algorithm::RSA_SHA1 => Some(digest_algorithm::SHA1),
signature_algorithm::RSA_SHA256 => Some(digest_algorithm::SHA256),
signature_algorithm::RSA_SHA256_MGF1 => Some(digest_algorithm::SHA256),
signature_algorithm::RSA_SHA384 => Some(digest_algorithm::SHA384),
signature_algorithm::RSA_SHA512 => Some(digest_algorithm::SHA512),
_ => None,
}
}
pub mod data_encryption_algorithm {
pub const AES_128: &str = "http://www.w3.org/2001/04/xmlenc#aes128-cbc";
pub const AES_256: &str = "http://www.w3.org/2001/04/xmlenc#aes256-cbc";
pub const TRIPLE_DES: &str = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc";
pub const AES_128_GCM: &str = "http://www.w3.org/2009/xmlenc11#aes128-gcm";
}
pub mod key_encryption_algorithm {
pub const RSA_OAEP_MGF1P: &str = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p";
pub const RSA_1_5: &str = "http://www.w3.org/2001/04/xmlenc#rsa-1_5";
}
pub mod transform_algorithm {
pub const ENVELOPED_SIGNATURE: &str = "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
pub const EXC_C14N: &str = "http://www.w3.org/2001/10/xml-exc-c14n#";
}
pub mod url_params {
pub const SAML_REQUEST: &str = "SAMLRequest";
pub const SAML_RESPONSE: &str = "SAMLResponse";
pub const SIG_ALG: &str = "SigAlg";
pub const SIGNATURE: &str = "Signature";
pub const RELAY_STATE: &str = "RelayState";
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CertUse {
Signing,
Encryption,
}
impl CertUse {
pub fn as_str(self) -> &'static str {
match self {
CertUse::Signing => "signing",
CertUse::Encryption => "encryption",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MessageSignatureOrder {
SignThenEncrypt,
EncryptThenSign,
}
impl MessageSignatureOrder {
pub fn as_str(self) -> &'static str {
match self {
MessageSignatureOrder::SignThenEncrypt => "sign-then-encrypt",
MessageSignatureOrder::EncryptThenSign => "encrypt-then-sign",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParserType {
SamlRequest,
SamlResponse,
LogoutRequest,
LogoutResponse,
}
impl ParserType {
pub fn as_str(self) -> &'static str {
match self {
ParserType::SamlRequest => "SAMLRequest",
ParserType::SamlResponse => "SAMLResponse",
ParserType::LogoutRequest => "LogoutRequest",
ParserType::LogoutResponse => "LogoutResponse",
}
}
pub fn query_param(self) -> &'static str {
match self {
ParserType::SamlRequest | ParserType::LogoutRequest => url_params::SAML_REQUEST,
ParserType::SamlResponse | ParserType::LogoutResponse => url_params::SAML_RESPONSE,
}
}
}
pub mod elements_order {
pub const DEFAULT: &[&str] = &[
"KeyDescriptor",
"NameIDFormat",
"SingleLogoutService",
"AssertionConsumerService",
];
pub const ONELOGIN: &[&str] = DEFAULT;
pub const SHIBBOLETH: &[&str] = &[
"KeyDescriptor",
"SingleLogoutService",
"NameIDFormat",
"AssertionConsumerService",
"AttributeConsumingService",
];
pub mod idp {
pub const DEFAULT: &[&str] = &[
"KeyDescriptor",
"NameIDFormat",
"SingleSignOnService",
"SingleLogoutService",
];
pub const ONELOGIN: &[&str] = &[
"KeyDescriptor",
"NameIDFormat",
"SingleLogoutService",
"SingleSignOnService",
];
pub const SHIBBOLETH: &[&str] = &[
"KeyDescriptor",
"SingleLogoutService",
"NameIDFormat",
"SingleSignOnService",
];
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn binding_urns_match_saml_spec_values() {
assert_eq!(
Binding::Redirect.urn(),
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
);
assert_eq!(
Binding::Post.urn(),
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
);
assert_eq!(
Binding::SimpleSign.urn(),
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
);
assert_eq!(
Binding::Artifact.urn(),
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
);
}
#[test]
fn binding_short_name_round_trip() {
for b in [
Binding::Redirect,
Binding::Post,
Binding::SimpleSign,
Binding::Artifact,
] {
assert_eq!(Binding::from_short_name(b.short_name()), Some(b));
assert_eq!(Binding::from_urn(b.urn()), Some(b));
}
assert_eq!(Binding::from_short_name("nope"), None);
assert_eq!(Binding::from_urn("nope"), None);
}
#[test]
fn parser_type_query_param() {
assert_eq!(ParserType::SamlRequest.query_param(), "SAMLRequest");
assert_eq!(ParserType::LogoutRequest.query_param(), "SAMLRequest");
assert_eq!(ParserType::SamlResponse.query_param(), "SAMLResponse");
assert_eq!(ParserType::LogoutResponse.query_param(), "SAMLResponse");
}
#[test]
fn digest_mapping_matches_xmlsig_values() {
assert_eq!(
digest_for_signature(signature_algorithm::RSA_SHA256),
Some(digest_algorithm::SHA256)
);
assert_eq!(
digest_for_signature(signature_algorithm::RSA_SHA256_MGF1),
Some(digest_algorithm::SHA256)
);
assert_eq!(
digest_for_signature(signature_algorithm::RSA_SHA1),
Some("http://www.w3.org/2000/09/xmldsig#sha1")
);
assert_eq!(digest_for_signature("unknown"), None);
}
#[test]
fn status_success_value() {
assert_eq!(
status_code::SUCCESS,
"urn:oasis:names:tc:SAML:2.0:status:Success"
);
}
#[test]
fn elements_order_profiles() {
assert_eq!(elements_order::DEFAULT.len(), 4);
assert_eq!(elements_order::ONELOGIN, elements_order::DEFAULT);
assert_eq!(elements_order::SHIBBOLETH[1], "SingleLogoutService");
}
}