uni-plugin 3.0.1

Plugin framework for uni-db: registry, manifest, and capability traits
Documentation
//! Authentication and authorization plugins.

/// Authentication credentials presented to an `AuthProvider`.
#[derive(Clone, Debug)]
pub enum Credentials {
    /// Username + password pair.
    Basic {
        /// Username.
        username: String,
        /// Password.
        password: String,
    },
    /// Bearer token.
    Bearer(String),
    /// mTLS client cert (DER-encoded).
    MtlsCert(Vec<u8>),
}

/// Successfully-authenticated identity.
#[derive(Clone, Debug)]
pub struct Principal {
    /// Identity string (subject id, username, etc.).
    pub id: String,
    /// Group memberships.
    pub groups: Vec<String>,
    /// Capabilities held by this principal.
    ///
    /// Populated by the host's authentication/authorization layer at
    /// principal-construction time — typically the
    /// [`AuthProvider`] / [`AuthzPolicy`] pair resolves group
    /// memberships to a [`crate::CapabilitySet`]. Procedure invocation
    /// paths (e.g.
    /// `uni.plugin.declareProcedure` for `WRITE` mode) gate on
    /// `principal.capabilities.contains_variant(&Capability::...)`.
    pub capabilities: crate::CapabilitySet,
}

impl Principal {
    /// Construct an anonymous principal with no capabilities — the
    /// safe default for unauthenticated paths.
    #[must_use]
    pub fn anonymous() -> Self {
        Self {
            id: "anonymous".to_owned(),
            groups: Vec::new(),
            capabilities: crate::CapabilitySet::new(),
        }
    }
}

/// Authentication failure cause.
#[derive(Clone, Debug, thiserror::Error)]
#[error("authentication failure: {0}")]
pub struct AuthError(pub String);

/// Authentication provider — `AuthProvider::authenticate(creds) -> Principal`.
pub trait AuthProvider: Send + Sync {
    /// Authentication scheme name (`"basic"`, `"bearer"`, `"mtls"`).
    fn scheme(&self) -> &str;

    /// Authenticate the given credentials.
    ///
    /// # Errors
    ///
    /// Returns [`AuthError`] if the credentials are invalid.
    fn authenticate(&self, credentials: &Credentials) -> Result<Principal, AuthError>;
}

/// Authorization action under check.
#[derive(Clone, Debug)]
pub struct Action {
    /// Action verb (`"read"`, `"write"`, `"delete"`, …).
    pub verb: String,
}

/// Authorization resource under check.
///
/// `path` is the raw query text (retained for backward compatibility); the
/// structured fields are extracted from the parsed query so a policy can gate on
/// vertex labels, relationship types, touched properties, and operations rather
/// than string-matching the Cypher. Empty structured fields mean "none found" or
/// "not extracted" — a policy should treat empties conservatively.
#[derive(Clone, Debug, Default)]
pub struct Resource {
    /// Raw query text / resource identifier.
    pub path: String,
    /// Vertex labels the query references.
    pub labels: Vec<String>,
    /// Relationship types the query references.
    pub rel_types: Vec<String>,
    /// Property keys the query reads or writes.
    pub properties: Vec<String>,
    /// Operations the query performs (`"read"`, `"write"`, `"delete"`, …).
    pub operations: Vec<String>,
}

/// Authorization decision.
#[derive(Clone, Debug)]
pub enum Decision {
    /// Permit the action.
    Allow,
    /// Deny with reason.
    Deny {
        /// Human-readable reason.
        reason: String,
    },
}

/// Authorization failure (policy errored out, not "denied").
#[derive(Clone, Debug, thiserror::Error)]
#[error("authorization policy failure: {0}")]
pub struct AuthzError(pub String);

/// Authorization policy plugin.
pub trait AuthzPolicy: Send + Sync {
    /// Check whether `principal` may perform `action` on `resource`.
    ///
    /// # Errors
    ///
    /// Returns [`AuthzError`] if the policy fails to evaluate (e.g.,
    /// external policy server unreachable).
    fn check(
        &self,
        principal: &Principal,
        action: &Action,
        resource: &Resource,
    ) -> Result<Decision, AuthzError>;
}