securitydept-token-set-context 0.3.0-beta.2

Token Set Context of SecurityDept, a layered authentication and authorization toolkit built as reusable Rust crates.
Documentation
use securitydept_oidc_client::PendingOauthStoreConfig;

use super::BackendOidcModeConfig;
use crate::backend_oidc_mode::PendingAuthStateMetadataRedemptionConfig;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BackendOidcModeConfigValidationError {
    pub mode: &'static str,
    pub field_path: String,
    pub code: String,
    pub message: String,
}

impl BackendOidcModeConfigValidationError {
    pub fn new(
        field_path: impl Into<String>,
        code: impl Into<String>,
        message: impl Into<String>,
    ) -> Self {
        Self {
            mode: "backend_oidc",
            field_path: field_path.into(),
            code: code.into(),
            message: message.into(),
        }
    }
}

impl std::fmt::Display for BackendOidcModeConfigValidationError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{} config validation failed for {} ({}): {}",
            self.mode, self.field_path, self.code, self.message
        )
    }
}

impl std::error::Error for BackendOidcModeConfigValidationError {}

pub trait BackendOidcModeConfigValidator {
    fn validate_raw_backend_oidc_mode_config<PC, MC>(
        &self,
        config: &BackendOidcModeConfig<PC, MC>,
    ) -> Result<(), BackendOidcModeConfigValidationError>
    where
        PC: PendingOauthStoreConfig,
        MC: PendingAuthStateMetadataRedemptionConfig;
}

#[derive(Debug, Clone, Copy, Default)]
pub struct NoopBackendOidcModeConfigValidator;

impl BackendOidcModeConfigValidator for NoopBackendOidcModeConfigValidator {
    fn validate_raw_backend_oidc_mode_config<PC, MC>(
        &self,
        _config: &BackendOidcModeConfig<PC, MC>,
    ) -> Result<(), BackendOidcModeConfigValidationError>
    where
        PC: PendingOauthStoreConfig,
        MC: PendingAuthStateMetadataRedemptionConfig,
    {
        Ok(())
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BackendOidcModeFixedRedirectUriValidator {
    redirect_url: String,
}

impl BackendOidcModeFixedRedirectUriValidator {
    pub fn new(redirect_url: impl Into<String>) -> Self {
        Self {
            redirect_url: redirect_url.into(),
        }
    }

    pub fn redirect_url(&self) -> &str {
        &self.redirect_url
    }
}

impl BackendOidcModeConfigValidator for BackendOidcModeFixedRedirectUriValidator {
    fn validate_raw_backend_oidc_mode_config<PC, MC>(
        &self,
        config: &BackendOidcModeConfig<PC, MC>,
    ) -> Result<(), BackendOidcModeConfigValidationError>
    where
        PC: PendingOauthStoreConfig,
        MC: PendingAuthStateMetadataRedemptionConfig,
    {
        if config.oidc_client.redirect_url.is_some() {
            return Err(BackendOidcModeConfigValidationError::new(
                "redirect_url",
                "fixed_redirect_uri_conflict",
                format!(
                    "backend redirect_url is fixed by the host to {} and cannot be overridden",
                    self.redirect_url
                ),
            ));
        }

        Ok(())
    }
}

impl<V> BackendOidcModeConfigValidator for &V
where
    V: BackendOidcModeConfigValidator + ?Sized,
{
    fn validate_raw_backend_oidc_mode_config<PC, MC>(
        &self,
        config: &BackendOidcModeConfig<PC, MC>,
    ) -> Result<(), BackendOidcModeConfigValidationError>
    where
        PC: PendingOauthStoreConfig,
        MC: PendingAuthStateMetadataRedemptionConfig,
    {
        (*self).validate_raw_backend_oidc_mode_config(config)
    }
}

impl<V> BackendOidcModeConfigValidator for [V]
where
    V: BackendOidcModeConfigValidator,
{
    fn validate_raw_backend_oidc_mode_config<PC, MC>(
        &self,
        config: &BackendOidcModeConfig<PC, MC>,
    ) -> Result<(), BackendOidcModeConfigValidationError>
    where
        PC: PendingOauthStoreConfig,
        MC: PendingAuthStateMetadataRedemptionConfig,
    {
        for validator in self {
            validator.validate_raw_backend_oidc_mode_config(config)?;
        }

        Ok(())
    }
}

impl<V, const N: usize> BackendOidcModeConfigValidator for [V; N]
where
    V: BackendOidcModeConfigValidator,
{
    fn validate_raw_backend_oidc_mode_config<PC, MC>(
        &self,
        config: &BackendOidcModeConfig<PC, MC>,
    ) -> Result<(), BackendOidcModeConfigValidationError>
    where
        PC: PendingOauthStoreConfig,
        MC: PendingAuthStateMetadataRedemptionConfig,
    {
        self.as_slice()
            .validate_raw_backend_oidc_mode_config(config)
    }
}

impl<V> BackendOidcModeConfigValidator for Vec<V>
where
    V: BackendOidcModeConfigValidator,
{
    fn validate_raw_backend_oidc_mode_config<PC, MC>(
        &self,
        config: &BackendOidcModeConfig<PC, MC>,
    ) -> Result<(), BackendOidcModeConfigValidationError>
    where
        PC: PendingOauthStoreConfig,
        MC: PendingAuthStateMetadataRedemptionConfig,
    {
        self.as_slice()
            .validate_raw_backend_oidc_mode_config(config)
    }
}

impl<A, B> BackendOidcModeConfigValidator for (A, B)
where
    A: BackendOidcModeConfigValidator,
    B: BackendOidcModeConfigValidator,
{
    fn validate_raw_backend_oidc_mode_config<PC, MC>(
        &self,
        config: &BackendOidcModeConfig<PC, MC>,
    ) -> Result<(), BackendOidcModeConfigValidationError>
    where
        PC: PendingOauthStoreConfig,
        MC: PendingAuthStateMetadataRedemptionConfig,
    {
        self.0.validate_raw_backend_oidc_mode_config(config)?;
        self.1.validate_raw_backend_oidc_mode_config(config)
    }
}

impl<A, B, C> BackendOidcModeConfigValidator for (A, B, C)
where
    A: BackendOidcModeConfigValidator,
    B: BackendOidcModeConfigValidator,
    C: BackendOidcModeConfigValidator,
{
    fn validate_raw_backend_oidc_mode_config<PC, MC>(
        &self,
        config: &BackendOidcModeConfig<PC, MC>,
    ) -> Result<(), BackendOidcModeConfigValidationError>
    where
        PC: PendingOauthStoreConfig,
        MC: PendingAuthStateMetadataRedemptionConfig,
    {
        self.0.validate_raw_backend_oidc_mode_config(config)?;
        self.1.validate_raw_backend_oidc_mode_config(config)?;
        self.2.validate_raw_backend_oidc_mode_config(config)
    }
}