Skip to main content

sova_scope/
ext.rs

1//! Request extensions for scoped authorization.
2
3use crate::engine::SharedEngine;
4use crate::plugin::ScopeAuthState;
5use crate::types::{Ability, Capabilities, Membership, ResourceRef, ScopeRef};
6use sova_core::{Error, Request, Result};
7use sova_db::DbExt;
8
9pub trait ScopeExt {
10    fn scope_engine(&self) -> Result<SharedEngine>;
11    fn scope_authorize(
12        &self,
13        scope: ScopeRef,
14        user_id: i64,
15        ability: Ability,
16        resource: Option<ResourceRef>,
17    ) -> impl std::future::Future<Output = Result<Capabilities>> + Send;
18    fn scope_effective(
19        &self,
20        scope: ScopeRef,
21        user_id: i64,
22        resource: Option<ResourceRef>,
23    ) -> impl std::future::Future<Output = Result<Capabilities>> + Send;
24    fn scope_membership(
25        &self,
26        scope: ScopeRef,
27        user_id: i64,
28    ) -> impl std::future::Future<Output = Result<Membership>> + Send;
29}
30
31impl ScopeExt for Request {
32    fn scope_engine(&self) -> Result<SharedEngine> {
33        self.try_state::<ScopeAuthState>()
34            .map(|s| s.engine.clone())
35            .ok_or_else(|| Error::Internal("ScopeAuth plugin not installed".into()))
36    }
37
38    async fn scope_authorize(
39        &self,
40        scope: ScopeRef,
41        user_id: i64,
42        ability: Ability,
43        resource: Option<ResourceRef>,
44    ) -> Result<Capabilities> {
45        let engine = self.scope_engine()?;
46        let db = self.db().clone();
47        engine.authorize(&db, scope, user_id, ability, resource).await
48    }
49
50    async fn scope_effective(
51        &self,
52        scope: ScopeRef,
53        user_id: i64,
54        resource: Option<ResourceRef>,
55    ) -> Result<Capabilities> {
56        let engine = self.scope_engine()?;
57        let db = self.db().clone();
58        engine.effective(&db, scope, user_id, resource).await
59    }
60
61    async fn scope_membership(&self, scope: ScopeRef, user_id: i64) -> Result<Membership> {
62        let engine = self.scope_engine()?;
63        let db = self.db().clone();
64        engine.require_member(&db, scope, user_id).await
65    }
66}