saml-rs 0.3.0

Pure-Rust SAML 2.0 Service Provider and Identity Provider support.
Documentation
use crate::browser::{LogoutBinding, SsoRequestBinding, SsoResponseBinding};
use crate::model::RelayStateParam;

/// Explicit `ForceAuthn` value for outbound AuthnRequests.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ForceAuthn {
    /// Emit `ForceAuthn="true"`.
    Required,
    /// Emit `ForceAuthn="false"`.
    NotRequired,
}

impl ForceAuthn {
    pub(super) fn as_bool(self) -> bool {
        match self {
            Self::Required => true,
            Self::NotRequired => false,
        }
    }
}

/// Options for starting SP-initiated Web SSO.
#[derive(Debug, Clone)]
pub struct StartSso {
    pub(super) binding: SsoRequestBinding,
    pub(super) response_binding: Option<SsoResponseBinding>,
    pub(super) relay_state: RelayStateParam,
    pub(super) force_authn: Option<ForceAuthn>,
    pub(super) acs_index: Option<u16>,
}

impl StartSso {
    /// Start SSO with HTTP-Redirect AuthnRequest dispatch.
    pub fn redirect() -> Self {
        Self::new(SsoRequestBinding::Redirect)
    }

    /// Start SSO with HTTP-POST AuthnRequest dispatch.
    pub fn post() -> Self {
        Self::new(SsoRequestBinding::Post)
    }

    /// Start SSO with HTTP-POST-SimpleSign AuthnRequest dispatch.
    pub fn simple_sign() -> Self {
        Self::new(SsoRequestBinding::SimpleSign)
    }

    fn new(binding: SsoRequestBinding) -> Self {
        Self {
            binding,
            response_binding: None,
            relay_state: RelayStateParam::absent(),
            force_authn: None,
            acs_index: None,
        }
    }

    /// Set the expected SAML Response binding.
    pub fn response_binding(mut self, binding: SsoResponseBinding) -> Self {
        self.response_binding = Some(binding);
        self
    }

    /// Set exact RelayState state for the outbound request.
    pub fn relay_state(mut self, relay_state: RelayStateParam) -> Self {
        self.relay_state = relay_state;
        self
    }

    /// Set the exact `ForceAuthn` value.
    pub fn force_authn(mut self, force_authn: ForceAuthn) -> Self {
        self.force_authn = Some(force_authn);
        self
    }

    /// Select an AssertionConsumerServiceIndex.
    pub fn assertion_consumer_service_index(mut self, acs_index: u16) -> Self {
        self.acs_index = Some(acs_index);
        self
    }
}

/// Options for issuing SAML Responses from an IdP.
#[derive(Debug, Clone)]
pub struct RespondSso {
    pub(super) binding: SsoResponseBinding,
    pub(super) relay_state: Option<RelayStateParam>,
}

impl RespondSso {
    /// Respond with HTTP-POST.
    pub fn post() -> Self {
        Self::new(SsoResponseBinding::Post)
    }

    /// Respond with HTTP-POST-SimpleSign.
    pub fn simple_sign() -> Self {
        Self::new(SsoResponseBinding::SimpleSign)
    }

    fn new(binding: SsoResponseBinding) -> Self {
        Self {
            binding,
            relay_state: None,
        }
    }

    /// Set exact RelayState state for the response.
    ///
    /// When omitted for a response to a received request, the received
    /// RelayState is echoed. Pass [`RelayStateParam::absent`] to suppress echo.
    pub fn relay_state(mut self, relay_state: RelayStateParam) -> Self {
        self.relay_state = Some(relay_state);
        self
    }
}

/// Explicit signing choice for typed Single Logout messages.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogoutSigning {
    /// Use the local typed logout policy.
    FollowLocalPolicy,
    /// Sign this logout message.
    Sign,
    /// Send unsigned logout for an explicit compatibility exception.
    DoNotSignForCompatibility,
}

/// Options for issuing a LogoutRequest.
#[derive(Debug, Clone)]
pub struct StartSlo {
    pub(super) binding: LogoutBinding,
    pub(super) relay_state: RelayStateParam,
    pub(super) signing: LogoutSigning,
}

impl StartSlo {
    /// Start SLO with HTTP-Redirect.
    pub fn redirect() -> Self {
        Self::new(LogoutBinding::Redirect)
    }

    /// Start SLO with HTTP-POST.
    pub fn post() -> Self {
        Self::new(LogoutBinding::Post)
    }

    /// Start SLO with HTTP-POST-SimpleSign.
    pub fn simple_sign() -> Self {
        Self::new(LogoutBinding::SimpleSign)
    }

    fn new(binding: LogoutBinding) -> Self {
        Self {
            binding,
            relay_state: RelayStateParam::absent(),
            signing: LogoutSigning::FollowLocalPolicy,
        }
    }

    /// Set exact RelayState state for the logout request.
    pub fn relay_state(mut self, relay_state: RelayStateParam) -> Self {
        self.relay_state = relay_state;
        self
    }

    /// Set logout request signing behavior.
    pub fn signing(mut self, signing: LogoutSigning) -> Self {
        self.signing = signing;
        self
    }
}

/// Options for issuing a LogoutResponse.
#[derive(Debug, Clone)]
pub struct RespondSlo {
    pub(super) binding: LogoutBinding,
    pub(super) relay_state: Option<RelayStateParam>,
    pub(super) signing: LogoutSigning,
}

impl RespondSlo {
    /// Respond with HTTP-Redirect.
    pub fn redirect() -> Self {
        Self::new(LogoutBinding::Redirect)
    }

    /// Respond with HTTP-POST.
    pub fn post() -> Self {
        Self::new(LogoutBinding::Post)
    }

    /// Respond with HTTP-POST-SimpleSign.
    pub fn simple_sign() -> Self {
        Self::new(LogoutBinding::SimpleSign)
    }

    fn new(binding: LogoutBinding) -> Self {
        Self {
            binding,
            relay_state: None,
            signing: LogoutSigning::FollowLocalPolicy,
        }
    }

    /// Set exact RelayState state for the logout response.
    ///
    /// When omitted, the received LogoutRequest RelayState is echoed. Pass
    /// [`RelayStateParam::absent`] to suppress echo.
    pub fn relay_state(mut self, relay_state: RelayStateParam) -> Self {
        self.relay_state = Some(relay_state);
        self
    }

    /// Set logout response signing behavior.
    pub fn signing(mut self, signing: LogoutSigning) -> Self {
        self.signing = signing;
        self
    }
}