sunbeam-g2v 0.4.0

Sunbeam Service Framework - A ConnectRPC-based framework for building microservices
//! Authentication and authorization errors.

use crate::error::ServiceError;
use std::fmt;

/// Errors originating in the authn/authz stack.
#[derive(Debug)]
pub enum AuthError {
    /// The supplied API key is invalid or unknown.
    InvalidApiKey,
    /// The tenant id is missing or malformed.
    InvalidTenant(String),
    /// The session cookie or token is invalid or expired.
    InvalidSession(String),
    /// The authorization backend returned an unexpected HTTP error response.
    AuthorizationBackend(String),
    /// The authorization backend could not be reached.
    AuthorizationBackendUnavailable(String),
    /// No tenant could be resolved for the request.
    MissingTenant,
    /// The subject does not have the requested permission.
    MissingPermission,
}

impl fmt::Display for AuthError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            AuthError::InvalidApiKey => write!(f, "invalid api key"),
            AuthError::InvalidTenant(msg) => write!(f, "invalid tenant: {msg}"),
            AuthError::InvalidSession(msg) => write!(f, "invalid session: {msg}"),
            AuthError::AuthorizationBackend(msg) => {
                write!(f, "authorization backend error: {msg}")
            }
            AuthError::AuthorizationBackendUnavailable(msg) => {
                write!(f, "authorization backend unavailable: {msg}")
            }
            AuthError::MissingTenant => write!(f, "missing tenant"),
            AuthError::MissingPermission => write!(f, "permission denied"),
        }
    }
}

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

impl From<AuthError> for ServiceError {
    fn from(err: AuthError) -> Self {
        match err {
            AuthError::InvalidApiKey
            | AuthError::InvalidTenant(_)
            | AuthError::InvalidSession(_)
            | AuthError::MissingTenant => ServiceError::Unauthenticated(err.to_string()),
            AuthError::MissingPermission => ServiceError::PermissionDenied(err.to_string()),
            AuthError::AuthorizationBackend(msg)
            | AuthError::AuthorizationBackendUnavailable(msg) => ServiceError::Internal(msg),
        }
    }
}