cedarling 0.0.64

The Cedarling: a high-performance local authorization service powered by the Rust Cedar Engine.
Documentation
// This software is available under the Apache-2.0 license.
// See https://www.apache.org/licenses/LICENSE-2.0.txt for full text.
//
// Copyright (c) 2024, Gluu, Inc.

use std::fmt::Display;

use super::build_expr::{BuildExprError, BuildExprErrorVec};
use super::entity_id_getters::GetEntityIdErrors;
use super::schema::BuildMappingSchemaError;
use cedar_policy::ExpressionConstructionError;
use smol_str::SmolStr;
use thiserror::Error;

#[derive(Debug, Error)]
pub(crate) enum InitEntityBuilderError {
    #[error("error while initializing trusted issuer entities: {0}")]
    BuildIssEntities(BuildEntityErrors),
    #[error("error while initializing the mapping schema: {0}")]
    BuildMappingSchema(#[from] BuildMappingSchemaError),
}

#[derive(Debug, Error)]
pub(crate) struct BuildEntityErrors(Vec<BuildEntityError>);

impl From<Vec<BuildEntityError>> for BuildEntityErrors {
    fn from(errors: Vec<BuildEntityError>) -> Self {
        Self(errors)
    }
}

impl Display for BuildEntityErrors {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "[{}]", collect_errors_to_str(&self.0))
    }
}

#[derive(Debug, Error)]
#[error("failed to build \"{entity_type_name}\" entity: {error}")]
pub struct BuildEntityError {
    pub entity_type_name: String,
    pub error: Box<BuildEntityErrorKind>,
}

impl BuildEntityError {
    pub fn new(entity_type_name: String, error: BuildEntityErrorKind) -> BuildEntityError {
        BuildEntityError {
            entity_type_name,
            error: Box::new(error),
        }
    }
}

#[derive(Debug, Error)]
pub enum BuildEntityErrorKind {
    #[error("unable to find a valid entity id, tried the following: {0}")]
    MissingEntityId(GetEntityIdErrors),
    #[error("failed to parse entity uid: {0}")]
    FailedToParseUid(#[from] Box<cedar_policy::ParseErrors>),
    #[error("failed to evaluate entity attribute or tag: {0}")]
    EntityAttrEval(#[from] Box<cedar_policy::EntityAttrEvaluationError>),
    #[error("invalid issuer URL: {0}")]
    InvalidIssUrl(#[from] url::ParseError),
    #[error("failed to build entity attributes: {0}")]
    BuildAttrs(#[from] BuildAttrsErrorVec),
    #[error("no available tokens to build the entity. missing one or more of the following: {0:?}")]
    NoAvailableTokensToBuildEntity(Vec<String>),
    #[error("the entity was not in the schema")]
    EntityNotInSchema,
    #[error("invalid entity data: {0}")]
    InvalidEntityData(String),
}

#[derive(Debug, Error)]
pub struct BuildAttrsErrorVec(pub Vec<BuildAttrsError>);

impl BuildAttrsErrorVec {
    pub fn into_inner(self) -> Vec<BuildAttrsError> {
        self.0
    }
}

impl From<Vec<BuildAttrsError>> for BuildEntityErrorKind {
    fn from(errs: Vec<BuildAttrsError>) -> Self {
        Self::BuildAttrs(BuildAttrsErrorVec(errs))
    }
}

impl From<BuildAttrsError> for BuildEntityErrorKind {
    fn from(err: BuildAttrsError) -> Self {
        Self::BuildAttrs(BuildAttrsErrorVec(Vec::from([err])))
    }
}

impl Display for BuildAttrsErrorVec {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "[{}]", collect_errors_to_str(&self.0))
    }
}

#[derive(Debug, Error)]
pub enum BuildAttrsError {
    #[error(transparent)]
    ExpressionConstruction(#[from] ExpressionConstructionError),
    #[error(transparent)]
    BuildRestrictedExpressions(#[from] BuildExprErrorVec),
    #[error("required entity references for {0:?} but none were found")]
    MissingEntityRefs(Vec<SmolStr>),
    #[error("missing the token claims required to build the entity: {0:?}")]
    MissingClaims(Vec<SmolStr>),
}

impl From<Vec<ExpressionConstructionError>> for BuildAttrsErrorVec {
    fn from(errs: Vec<ExpressionConstructionError>) -> Self {
        Self(
            errs.into_iter()
                .map(BuildAttrsError::ExpressionConstruction)
                .collect(),
        )
    }
}

impl From<Box<BuildExprError>> for BuildAttrsError {
    fn from(err: Box<BuildExprError>) -> Self {
        Self::BuildRestrictedExpressions(BuildExprErrorVec::from(Vec::from([err])))
    }
}

impl BuildEntityErrorKind {
    pub fn while_building(self, entity_type_name: &str) -> BuildEntityError {
        BuildEntityError {
            entity_type_name: entity_type_name.to_string(),
            error: Box::new(self),
        }
    }
}

fn collect_errors_to_str<T: Display>(errors: &[T]) -> String {
    errors
        .iter()
        .map(ToString::to_string)
        .collect::<Vec<_>>()
        .join(", ")
}

#[derive(Debug, Error)]
pub enum BuildUnsignedEntityError {
    #[error("the role entity must be either a String or an Array of strings but got: {0:?}")]
    InvalidType(serde_json::Value),
    #[error(transparent)]
    BuildEntity(#[from] Box<BuildEntityError>),
}