Skip to main content

uni_plugin/traits/
connector.rs

1//! Wire-protocol connector plugins.
2
3use crate::errors::FnError;
4
5/// Free-form connector configuration (JSON-encoded).
6#[derive(Clone, Debug, Default)]
7pub struct ConnectorConfig {
8    /// JSON config payload.
9    pub config_json: String,
10}
11
12/// Opaque handle returned by [`Connector::start`].
13#[derive(Clone, Copy, Debug)]
14pub struct ConnectorHandle(pub u64);
15
16/// A wire-protocol connector — Bolt, GraphQL, REST, etc.
17pub trait Connector: Send + Sync {
18    /// Protocol name (`"bolt"`, `"graphql"`, …).
19    fn protocol(&self) -> &str;
20
21    /// Start the connector with the given configuration.
22    ///
23    /// # Errors
24    ///
25    /// Returns [`FnError`] if the connector cannot start (bind failure,
26    /// missing dependency).
27    fn start(&self, cfg: ConnectorConfig) -> Result<ConnectorHandle, FnError>;
28
29    /// Stop the connector.
30    ///
31    /// # Errors
32    ///
33    /// Returns [`FnError`] if the shutdown fails.
34    fn stop(&self, handle: ConnectorHandle) -> Result<(), FnError>;
35}
36
37/// Authentication credentials presented to an `AuthProvider`.
38#[derive(Clone, Debug)]
39pub enum Credentials {
40    /// Username + password pair.
41    Basic {
42        /// Username.
43        username: String,
44        /// Password.
45        password: String,
46    },
47    /// Bearer token.
48    Bearer(String),
49    /// mTLS client cert (DER-encoded).
50    MtlsCert(Vec<u8>),
51}
52
53/// Successfully-authenticated identity.
54#[derive(Clone, Debug)]
55pub struct Principal {
56    /// Identity string (subject id, username, etc.).
57    pub id: String,
58    /// Group memberships.
59    pub groups: Vec<String>,
60    /// Capabilities held by this principal.
61    ///
62    /// Populated by the host's authentication/authorization layer at
63    /// principal-construction time — typically the
64    /// [`AuthProvider`] / [`AuthzPolicy`] pair resolves group
65    /// memberships to a [`crate::CapabilitySet`]. Procedure invocation
66    /// paths (e.g.
67    /// `uni.plugin.declareProcedure` for `WRITE` mode) gate on
68    /// `principal.capabilities.contains_variant(&Capability::...)`.
69    pub capabilities: crate::CapabilitySet,
70}
71
72impl Principal {
73    /// Construct an anonymous principal with no capabilities — the
74    /// safe default for unauthenticated paths.
75    #[must_use]
76    pub fn anonymous() -> Self {
77        Self {
78            id: "anonymous".to_owned(),
79            groups: Vec::new(),
80            capabilities: crate::CapabilitySet::new(),
81        }
82    }
83}
84
85/// Authentication failure cause.
86#[derive(Clone, Debug, thiserror::Error)]
87#[error("authentication failure: {0}")]
88pub struct AuthError(pub String);
89
90/// Authentication provider — `AuthProvider::authenticate(creds) -> Principal`.
91pub trait AuthProvider: Send + Sync {
92    /// Authentication scheme name (`"basic"`, `"bearer"`, `"mtls"`).
93    fn scheme(&self) -> &str;
94
95    /// Authenticate the given credentials.
96    ///
97    /// # Errors
98    ///
99    /// Returns [`AuthError`] if the credentials are invalid.
100    fn authenticate(&self, credentials: &Credentials) -> Result<Principal, AuthError>;
101}
102
103/// Authorization action under check.
104#[derive(Clone, Debug)]
105pub struct Action {
106    /// Action verb (`"read"`, `"write"`, `"delete"`, …).
107    pub verb: String,
108}
109
110/// Authorization resource under check.
111#[derive(Clone, Debug)]
112pub struct Resource {
113    /// Resource path / identifier.
114    pub path: String,
115}
116
117/// Authorization decision.
118#[derive(Clone, Debug)]
119pub enum Decision {
120    /// Permit the action.
121    Allow,
122    /// Deny with reason.
123    Deny {
124        /// Human-readable reason.
125        reason: String,
126    },
127}
128
129/// Authorization failure (policy errored out, not "denied").
130#[derive(Clone, Debug, thiserror::Error)]
131#[error("authorization policy failure: {0}")]
132pub struct AuthzError(pub String);
133
134/// Authorization policy plugin.
135pub trait AuthzPolicy: Send + Sync {
136    /// Check whether `principal` may perform `action` on `resource`.
137    ///
138    /// # Errors
139    ///
140    /// Returns [`AuthzError`] if the policy fails to evaluate (e.g.,
141    /// external policy server unreachable).
142    fn check(
143        &self,
144        principal: &Principal,
145        action: &Action,
146        resource: &Resource,
147    ) -> Result<Decision, AuthzError>;
148}