arc-auth-core 0.7.2

Composable identity and authorization contracts for Arc
Documentation
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use thiserror::Error;

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Identity {
    pub id: String,
    pub name: String,
    pub email: String,
    pub active: bool,
    pub roles: Vec<String>,
}

impl Identity {
    pub fn has_role(&self, role: &str) -> bool {
        self.roles.iter().any(|assigned| assigned == role)
    }
}

#[derive(Debug, Error)]
pub enum AuthError {
    #[error("invalid credentials")]
    InvalidCredentials,
    #[error("identity not found")]
    NotFound,
    #[error("email is already registered")]
    DuplicateEmail,
    #[error("invalid input: {0}")]
    InvalidInput(String),
    #[error("identity store unavailable: {0}")]
    Store(String),
}

#[async_trait]
pub trait IdentityStore: Send + Sync {
    async fn authenticate(&self, email: &str, password: &str) -> Result<Identity, AuthError>;
    async fn get(&self, id: &str) -> Result<Option<Identity>, AuthError>;
    async fn list(&self) -> Result<Vec<Identity>, AuthError>;
    async fn has_users(&self) -> Result<bool, AuthError>;
    async fn create_user(
        &self,
        name: &str,
        email: &str,
        password: &str,
        roles: &[String],
    ) -> Result<Identity, AuthError>;
    async fn update_profile(
        &self,
        id: &str,
        name: &str,
        email: &str,
    ) -> Result<Identity, AuthError>;
    async fn change_password(&self, id: &str, password: &str) -> Result<(), AuthError>;
    async fn set_roles(&self, id: &str, roles: &[String]) -> Result<Identity, AuthError>;
}

pub trait AuthorizationPolicy: Send + Sync {
    fn permits(&self, identity: &Identity, required_roles: &[&str]) -> bool;
}