saml-rs 0.3.0

Pure-Rust SAML 2.0 Service Provider and Identity Provider support.
Documentation
#[cfg(feature = "crypto-bergshamra")]
use crate::binding::base64_encode;
use crate::constants::{Binding, ParserType};
use crate::entity::EntitySetting;
use crate::error::SamlError;

#[cfg(feature = "crypto-bergshamra")]
pub(super) fn sign_logout(
    setting: &EntitySetting,
    binding: Binding,
    xml: &str,
    destination: &str,
    relay: Option<&str>,
    parser_type: ParserType,
) -> Result<(String, Option<String>, Option<String>), SamlError> {
    use crate::binding::{append_signature, build_redirect_octet};
    use crate::crypto::{
        construct_message_signature, construct_saml_signature, keys::load_private_key,
    };

    if matches!(binding, Binding::Artifact) {
        return Err(SamlError::UnsupportedBinding {
            binding: Binding::Artifact,
        });
    }

    let sig_alg = &setting.request_signature_algorithm;
    let key_pem = setting
        .private_key
        .as_deref()
        .ok_or_else(|| SamlError::MissingKey("private_key".into()))?;
    let key = load_private_key(key_pem, setting.private_key_pass.as_deref())?;
    match binding {
        Binding::Redirect => {
            let octet = build_redirect_octet(parser_type, xml, relay, sig_alg)?;
            let sig = construct_message_signature(&octet, &key, sig_alg)?;
            Ok((append_signature(destination, &octet, &sig), None, None))
        }
        Binding::Post => {
            let cert = setting
                .signing_cert
                .as_deref()
                .ok_or_else(|| SamlError::MissingKey("signing_cert".into()))?;
            let signed = construct_saml_signature(
                xml,
                true,
                &key,
                cert,
                sig_alg,
                &setting.transformation_algorithms,
                setting.signature_config.as_ref(),
            )?;
            Ok((base64_encode(signed.as_bytes()), None, None))
        }
        Binding::SimpleSign => {
            let octet = crate::binding::build_simplesign_octet(
                parser_type.query_param(),
                xml,
                relay,
                sig_alg,
            );
            let sig = construct_message_signature(&octet, &key, sig_alg)?;
            Ok((
                base64_encode(xml.as_bytes()),
                Some(sig),
                Some(sig_alg.clone()),
            ))
        }
        Binding::Artifact => Err(SamlError::UnsupportedBinding {
            binding: Binding::Artifact,
        }),
    }
}

#[cfg(not(feature = "crypto-bergshamra"))]
pub(super) fn sign_logout(
    _setting: &EntitySetting,
    _binding: Binding,
    _xml: &str,
    _destination: &str,
    _relay: Option<&str>,
    _parser_type: ParserType,
) -> Result<(String, Option<String>, Option<String>), SamlError> {
    Err(SamlError::Unsupported(
        "signing logout messages requires feature crypto-bergshamra".into(),
    ))
}