use crate::browser::{LogoutBinding, SsoRequestBinding, SsoResponseBinding};
use crate::model::{RelayStateParam, Status};
use crate::sp::WebBrowserSsoProducer;
pub use crate::model::{ForceAuthn, IsPassive};
#[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>,
pub(super) web_browser_sso_producer: WebBrowserSsoProducer,
}
impl StartSso {
pub fn redirect() -> Self {
Self::new(SsoRequestBinding::Redirect)
}
pub fn post() -> Self {
Self::new(SsoRequestBinding::Post)
}
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,
web_browser_sso_producer: WebBrowserSsoProducer::Compatibility,
}
}
pub fn response_binding(mut self, binding: SsoResponseBinding) -> Self {
self.response_binding = Some(binding);
self
}
pub fn relay_state(mut self, relay_state: RelayStateParam) -> Self {
self.relay_state = relay_state;
self
}
pub fn force_authn(mut self, force_authn: ForceAuthn) -> Self {
self.force_authn = Some(force_authn);
self
}
pub fn assertion_consumer_service_index(mut self, acs_index: u16) -> Self {
self.acs_index = Some(acs_index);
self
}
pub fn apply_web_browser_sso_generation_rules(mut self) -> Self {
self.web_browser_sso_producer = WebBrowserSsoProducer::Follow;
self
}
}
#[derive(Debug, Clone)]
pub struct RespondSso {
pub(super) binding: SsoResponseBinding,
pub(super) relay_state: Option<RelayStateParam>,
response_signing: ResponseSigning,
pub(super) web_browser_sso_producer: WebBrowserSsoProducer,
pub(super) status: Option<Status>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ResponseSigning {
FollowEncryptedCbcRecommendation,
Always,
AllowUnsignedEncryptedCbc,
}
impl RespondSso {
pub fn post() -> Self {
Self::new(SsoResponseBinding::Post)
}
pub fn simple_sign() -> Self {
Self::new(SsoResponseBinding::SimpleSign)
}
fn new(binding: SsoResponseBinding) -> Self {
Self {
binding,
relay_state: None,
response_signing: ResponseSigning::FollowEncryptedCbcRecommendation,
web_browser_sso_producer: WebBrowserSsoProducer::Compatibility,
status: None,
}
}
pub fn status(mut self, status: Status) -> Self {
self.status = Some(status);
self
}
pub fn sign_response(mut self) -> Self {
self.response_signing = ResponseSigning::Always;
self
}
pub fn allow_unsigned_encrypted_cbc(mut self) -> Self {
self.response_signing = ResponseSigning::AllowUnsignedEncryptedCbc;
self
}
pub fn apply_web_browser_sso_generation_rules(mut self) -> Self {
self.web_browser_sso_producer = WebBrowserSsoProducer::Follow;
self
}
pub fn relay_state(mut self, relay_state: RelayStateParam) -> Self {
self.relay_state = Some(relay_state);
self
}
pub(super) fn should_sign_response(
&self,
assertion_encrypted: bool,
data_encryption_algorithm: &str,
) -> bool {
match self.response_signing {
ResponseSigning::FollowEncryptedCbcRecommendation => {
assertion_encrypted
&& crate::constants::is_xml_encryption_cbc_algorithm(data_encryption_algorithm)
}
ResponseSigning::Always => true,
ResponseSigning::AllowUnsignedEncryptedCbc => false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogoutSigning {
FollowLocalPolicy,
Sign,
DoNotSignForCompatibility,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
enum SingleLogoutGeneration {
#[default]
Compatibility,
Follow,
}
impl SingleLogoutGeneration {
fn follows(self) -> bool {
matches!(self, Self::Follow)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
enum ParticipantLogoutTransport {
#[default]
RequireHttps,
AllowHttp,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
struct SingleLogoutRules {
generation: SingleLogoutGeneration,
transport: ParticipantLogoutTransport,
}
impl SingleLogoutRules {
fn apply_generation_rules(mut self) -> Self {
self.generation = SingleLogoutGeneration::Follow;
self
}
fn allow_http(mut self) -> Self {
self.transport = ParticipantLogoutTransport::AllowHttp;
self
}
fn follows(self) -> bool {
self.generation.follows()
}
fn allows_http(self) -> bool {
matches!(self.transport, ParticipantLogoutTransport::AllowHttp)
}
}
#[derive(Debug, Clone)]
pub struct StartSlo {
pub(super) binding: LogoutBinding,
pub(super) relay_state: RelayStateParam,
pub(super) signing: LogoutSigning,
rules: SingleLogoutRules,
}
impl StartSlo {
pub fn redirect() -> Self {
Self::new(LogoutBinding::Redirect)
}
pub fn post() -> Self {
Self::new(LogoutBinding::Post)
}
pub fn simple_sign() -> Self {
Self::new(LogoutBinding::SimpleSign)
}
fn new(binding: LogoutBinding) -> Self {
Self {
binding,
relay_state: RelayStateParam::absent(),
signing: LogoutSigning::FollowLocalPolicy,
rules: SingleLogoutRules::default(),
}
}
pub fn relay_state(mut self, relay_state: RelayStateParam) -> Self {
self.relay_state = relay_state;
self
}
pub fn signing(mut self, signing: LogoutSigning) -> Self {
self.signing = signing;
self
}
pub fn apply_single_logout_generation_rules(mut self) -> Self {
self.rules = self.rules.apply_generation_rules();
self
}
pub fn allow_http_single_logout(mut self) -> Self {
self.rules = self.rules.allow_http();
self
}
pub(super) fn follows_generation_rules(&self) -> bool {
self.rules.follows()
}
pub(super) fn allows_http(&self) -> bool {
self.rules.allows_http()
}
}
#[derive(Debug, Clone)]
pub struct RespondSlo {
pub(super) binding: LogoutBinding,
pub(super) relay_state: Option<RelayStateParam>,
pub(super) status: Option<Status>,
rules: SingleLogoutRules,
}
impl RespondSlo {
pub fn redirect() -> Self {
Self::new(LogoutBinding::Redirect)
}
pub fn post() -> Self {
Self::new(LogoutBinding::Post)
}
pub fn simple_sign() -> Self {
Self::new(LogoutBinding::SimpleSign)
}
fn new(binding: LogoutBinding) -> Self {
Self {
binding,
relay_state: None,
status: None,
rules: SingleLogoutRules::default(),
}
}
pub fn status(mut self, status: Status) -> Self {
self.status = Some(status);
self
}
pub fn relay_state(mut self, relay_state: RelayStateParam) -> Self {
self.relay_state = Some(relay_state);
self
}
pub fn apply_single_logout_generation_rules(mut self) -> Self {
self.rules = self.rules.apply_generation_rules();
self
}
pub fn allow_http_single_logout(mut self) -> Self {
self.rules = self.rules.allow_http();
self
}
pub(super) fn follows_generation_rules(&self) -> bool {
self.rules.follows()
}
pub(super) fn allows_http(&self) -> bool {
self.rules.allows_http()
}
}